Можно ли специализировать шаблон по языковой привязке?

Языковая связь функции является частью ее типа:

7.5.1 [dcl.link] стандарта ISO C++:

Языковая связь по умолчанию для всех типов функций, имен функций и имен переменных — это языковая связь C++. Два типа функций с разными языковыми связями являются разными типами, даже если в остальном они идентичны.

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

Эта первая попытка не кажется законной:

#include <iostream>
#include <typeinfo>

struct cpp {};
struct c {};

extern "C++" void foo()
{
  std::cout << "foo" << std::endl;
}

extern "C" void bar()
{
  std::cout << "bar" << std::endl;
}

template<typename> struct linkage;

template<>
  struct linkage<void(*)()>
{
  typedef cpp type;
};

template<>
  struct linkage<extern "C" void(*)()>
{
  typedef c type;
}


int main()
{
  std::cout << "linkage of foo: " << typeid(linkage<decltype(&foo)>::type).name() << std::endl;
  std::cout << "linkage of bar: " << typeid(linkage<decltype(&bar)>::type).name() << std::endl;
  return 0;
}

g++-4.6 выходы:

$ g++ -std=c++0x test.cpp 
test.cpp:26:38: error: template argument 1 is invalid
test.cpp:26:3: error: new types may not be defined in a return type
test.cpp:26:3: note: (perhaps a semicolon is missing after the definition of ‘<type error>’)
test.cpp:32:10: error: two or more data types in declaration of ‘main’

Есть ли какое-то приложение SFINAE, которое могло бы реализовать эту функциональность?


person Jared Hoberock    schedule 12.10.2012    source источник


Ответы (1)


Да, я считаю, что вы должны иметь возможность специализировать шаблон на основе его языковой связи в соответствии со стандартом C++. Я протестировал следующий код с помощью онлайн-компилятора Comeau, и он скомпилировался без ошибок:

#include <iostream>
#include <typeinfo>

struct cpp {};
struct c {};

extern "C++" typedef void(*cppfunc)();
extern "C" typedef void(*cfunc)();

extern "C++" void foo()
{
  std::cout << "foo" << std::endl;
}

extern "C" void bar()
{
  std::cout << "bar" << std::endl;
}

template<typename> struct linkage;

template<>
  struct linkage<cppfunc>
{
  typedef cpp type;
};

template<>
  struct linkage<cfunc>
{
  typedef c type;
};


int main()
{
  std::cout << "linkage of foo: " << typeid(linkage<decltype(&foo)>::type).name() << std::endl;
  std::cout << "linkage of bar: " << typeid(linkage<decltype(&bar)>::type).name() << std::endl;
  return 0;
}

Однако я считаю, что из-за ошибки gcc gcc не различает типы функций основаны на привязке к языку, поэтому это невозможно с gcc (и неясно, когда они это исправят).

person Jesse Good    schedule 13.10.2012
comment
Возможно, у вас есть цитата из спецификации, в которой говорится, что связь является частью информации о типе, на которой основаны шаблоны C++? - person Nicol Bolas; 13.10.2012
comment
@NicolBolas: Нет, не знаю. Однако я думаю, что цитата в вопросе ясна: Two function types with different language linkages are distinct types. И из [14.4 Эквивалентность типов]: Two template-ids refer to the same class or function if their corresponding type template-arguments are the same type. - person Jesse Good; 13.10.2012