Подтвердить что ты не робот

Указатели на разные экземпляры одной шаблонной функции гарантируют сравнение неравных?

Можно ли предположить, что два указателя функций, указывающие на разные экземпляры одной шаблонной функции, будут сравнивать неравные? Даже если шаблонная функция вообще не использует параметр шаблона и, таким образом, делает то же самое в каждом случае?

Например, следующее работает отлично в моем компиляторе, но я не уверен, что он делает это на любом другом:

class TypeChecker
{
public:
    template< typename T > static void foo( void )
    {}
    template< typename T > static void setType( void )
    { s_fooPtr = &foo< T >; }
    template< typename T > static bool checkType( void )
    { return ( s_fooPtr == &foo< T > ); }
private:
    static void ( * s_fooPtr )( void );
};

void ( * TypeChecker::s_fooPtr )( void ) = 0;

int main( void )
{
    TypeChecker::setType< char >();
    TypeChecker::checkType< char >();           // true
    TypeChecker::checkType< unsigned char >();  // false
    TypeChecker::checkType< signed char >();    // false
}
4b9b3361

Ответ 1

Когда два указателя сравниваются равными?

Согласно 5.10/1:

Операторы == (равно) и a = = (не равные) имеют одинаковые семантические ограничения, преобразования и тип результата в качестве реляционных операторов, за исключением их более низкого приоритета и результата истины. [ Примечание: a<b == c<d истинно, если a<b и c<d имеют одинаковое значение истинности. -end note] Указатели того же типа (после конверсий указателей) могут быть по сравнению с равенством. Два указателя одного типа сравниваются, если и только если оба они равны нулю, оба указывают на одну и ту же функцию, или оба представляют один и тот же адрес (3.9.2).

Существуют ли foo<int>() и foo<char>() те же функции?

Согласно 14.4/1:

Два идентификатора шаблона относятся к одному и тому же классу или функции, если

  • их имена шаблонов, идентификаторы-операторы-операторы или литеральные -операторы-идентификаторы относятся к одному и тому же шаблону и
  • их соответствующие шаблоны-аргументы типа одного типа и
  • их соответствующие аргументы несимметричного шаблона интегрального или перечисляемого типа имеют одинаковые значения и
  • соответствующие им не-тип шаблона-аргументы типа указателя относятся к одному и тому же внешнему объекту или или оба являются значениями нулевого указателя и
  • их соответствующие шаблонные аргументы типа non-type типа "указатель-член" относятся к одному классу член или оба являются значениями указателя нулевого элемента и
  • их соответствующие шаблоны-аргументы типа non-type ссылочного типа относятся к одному и тому же внешнему объекту или функции и
  • их соответствующие шаблонные шаблоны шаблона относятся к одному и тому же шаблону.

Таким образом, очевидно, что foo<int>() и foo<char>() не являются одной и той же функцией.

Так что &foo<int>() и &foo<char>() не должны сравниваться одинаково, независимо от того, какая оптимизация выполнена.


EDIT:

Как упоминалось в комментарии @SergeDundich, в 14.4/1 вместо if вместо if and only if использовался if, который дает нет гарантию того, являются ли теги foo<int>() и foo<char>() или нет. В других частях спецификации if and only if используется много.

В спецификации я не нашел пояснений. Однако в примерах я могу найти это:

template<class T, void(*err_fct)()> class list { /* ... */ };
list<int,&error_handler1> x1;
list<int,&error_handler2> x2;
list<int,&error_handler2> x3;
list<char,&error_handler2> x4;

объявляет x2 и x3 одинаковыми. Их тип отличается от типы x1 и x4.


EDIT2:

if используется вместо if and only if, поскольку такая ситуация существует: (Пример из 14.5.7/2)

template<class T> struct Alloc { /* ... */ };
template<class T> using Vec = vector<T, Alloc<T>>;
Vec<int> v; // same as vector<int, Alloc<int>> v;

Vec<int> и vector<int, Alloc<int>> имеют много различий, но все тот же тип.

Однако, что касается случая foo<int>() и foo<char>(), их подписи различны. Различные подписи должны предоставлять им разные функции.

Благодаря @JohannesSchaub-litb.