Запретить создание определенного экземпляра функции
Я хотел бы определить функцию шаблона, но запретить создание экземпляра с определенным типом. Обратите внимание, что в целом разрешены все типы и общий шаблон работает, я просто хочу запретить использование нескольких конкретных типов.
Например, в приведенном ниже коде я хочу предотвратить использование 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'