Запретить создание определенного экземпляра функции

Я хотел бы определить функцию шаблона, но запретить создание экземпляра с определенным типом. Обратите внимание, что в целом разрешены все типы и общий шаблон работает, я просто хочу запретить использование нескольких конкретных типов.

Например, в приведенном ниже коде я хочу предотвратить использование double с помощью шаблона. Это фактически не предотвращает создание экземпляра, а просто вызывает ошибку компоновщика, не определяя определенную функцию.

template<typename T>
T convert( char const * in )
{ return T(); }

//this way creates a linker error
template<>
double convert<double>( char const * in );

int main()
{
    char const * str = "1234";

    int a = convert<int>( str );
    double b = convert<double>( str );
}

Код - это просто демонстрация, очевидно, что функция преобразования должна делать что-то еще.

Вопрос: В приведенном выше коде как я могу создать ошибку компилятора при попытке использовать экземпляр convert<double>?


Ближайший связанный вопрос, который я могу найти, Как преднамеренно вызвать ошибку времени компиляции при создании экземпляра шаблона. Он относится к классу, а не к функции.

Причина, по которой мне нужно это сделать, - это то, что типы, которые я хочу заблокировать, будут фактически компилироваться и делать что-то с общей версией. Это, однако, не должно быть частью контракта функции и может не поддерживаться на всех платформах/компиляторах и в будущих версиях. Поэтому я хотел бы вообще не использовать его.

Ответ 1

Я бы использовал статическое утверждение в вызове функции для создания правильного сбоя во время создания функции:

template<typename T>
class is_double{ static const int value = false; }

template<>
class is_double<double>{ static const int value = true; }

template<typename T>
T convert( const char *argument ){
    BOOST_STATIC_ASSERT( !is_double<T>::value );
    //rest of code
}

И это должно работать внутри функции.

Ответ 2

Вместо функции можно использовать функтор:

template<typename T>
struct convert { 
    T operator()(char const * in) const { return T(); } 
};
template<> struct convert<double>;

int main()
{
    char const * str = "1234";

    int a = convert<int>()( str );
    double b = convert<double>()( str ); // error in this line

    return 0;
}

Это даст вам ошибку в момент создания экземпляра.

Добавив вспомогательную функцию, вы получите желаемое поведение:

template<typename T>
struct convert_helper { 
    T operator()(char const * in) const { return T(); } 
};
template<> struct convert_helper<double>;

template<typename T>
T convert( char const * in ) { return convert_helper<T>()( in ); }

int main()
{
    char const * str = "1234";

    int a = convert<int>( str );
    double b = convert<double>( str );

    return 0;
}

Ответ 3

Если вы не хотите полагаться на static_assert или сделать код переносимым pre-С++ 0x, используйте это:

template<class T>
void func(){
    typedef char ERROR_in_the_matrix[std::is_same<T,double>::value? -1 : 1];
}

int main(){
  func<int>(); // no error
  func<double>(); // error: negative subscript
}

Ответ 4

Рассмотрим Boost disable_if и Boost TypeTraits

Взгляните на Как написать шаблон функции для всех типов с определенной чертой типа?

Это пример:

#include <boost/type_traits.hpp>
#include <boost/utility/enable_if.hpp>

template<typename T>
T convert( char const * in, 
           typename boost::disable_if<boost::is_floating_point<T>, T>::type* = 0 )
{ return T(); }


int main()
{
    char const * str = "1234";

    int a = convert<int>( str );
    double b = convert<double>( str );
    return 0;
}


Это ошибка компиляции для строки

double b = convert<double>( str );

1 > .\simple_no_stlport.cpp(14): ошибка C2770: неверный шаблон аргумент для 'T convert (const char* Повышение:: disable_if, T > :: тип *) '1 > .\Simple_no_stlport.cpp(5): см. Объявление 'convert'