Сопоставление символов специализации шаблонных функций в разных библиотеках
До сих пор у меня была установка, где определенный шаблон функции getF
было объявлено так в заголовках
template <typename T> F* getF();
оставляя тело функции неопределенным. Затем в общей библиотеке, getF
имеет некоторые специализации..
template<>
F* getF<int>()
{
static int r = 42;
static Finstance(r);
return &Finstance;
}
template<>
F* getF<float>()
{
static float r = 3.14159;
static Finstance(r);
return &Finstance;
}
Вышесказанное хорошо работает, когда я запускаю клиентский исполняемый файл getF<float>()
, компоновщик заменит соответствующие ссылки, и если специализация не существует в библиотеке, то компиляция завершится с ошибкой компоновщика (что было желаемым поведением)
Однако теперь должно произойти небольшое изменение в поведении: когда результат не специализирован для данного параметра шаблона, код должен собираться, но возвращать 0 во время выполнения. Так что я сделал, это изменить декларацию getF
как это:
template <typename T> F* getF() { return 0; }
Проблема в том, что теперь компилятор будет использовать это определение для всех случаев, независимо от того, есть ли специализация в библиотеке
Вопрос: Есть ли другой способ обеспечить поведение по умолчанию для функции во время выполнения, не перемещая специализации в заголовочные файлы?
2 ответа
Лучшее решение - объявить о существовании явных специализаций библиотеки.
// All in the same header file:
template <typename T> F* getF() { return 0; }
template <> F* getF<int>();
template <> F* getF<float>();
Это удовлетворяет правилу из стандарта 14.7.3/6:
Если шаблон, шаблон элемента или элемент шаблона класса явно специализированы, то эта специализация должна быть объявлена до первого использования этой специализации, которая вызовет неявную реализацию в каждой единице перевода, в которой такое использование происходит.; Диагностика не требуется.
По сути, вы хотите следующее: "включить особые случаи F, когда T является int или float". Это именно то, о чем говорят такие конструкции, как boost::enable_if и std::enable_if.
Есть тонкие различия в включении / отключении функций по сравнению с классами (классы проще). Смотрите хорошие примеры здесь: boost::enable_if не в сигнатуре функции
Вам может понадобиться некоторая MPL (Boost Meta-Program Library), чтобы выразить "или" часть вашего правила.