Ограничить тип параметра в создании шаблона - PullRequest
5 голосов
/ 16 июня 2011

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

template <typename T>
struct good_type { enum { value = false }; };

template <>
struct good_type<string> { enum { value = true }; };

template <>
struct good_type<int64_t> { enum { value = true }; };

template <typename T>
struct X
{
  BOOST_STATIC_ASSERT(good_type<T>::value);
};

int main(int argc, char** argv)
{
  X<string> x1; 
  X<int64_t> x2;
  X<float> x3; 
  return 0;
}

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

error: invalid application of 'sizeof' to incomplete type 'boost::STATIC_ASSERTION_FAILURE<false>' 

Должен ли я использовать другой макрос Boost? Есть ли лучший способ сделать это?

Спасибо!

Ответы [ 4 ]

5 голосов
/ 16 июня 2011

Вы можете использовать boost::enable_if вместе с набором типов.

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


Хорошо, я написал код для демонстрации. Тем не менее, он не использует boost::enable_if (для экспериментов).

Вот рамки в первую очередь:

////////////////////////////////////////////////////////////
//framework

struct null_type {};

template<typename H, typename  T=null_type>
struct typelist
{
   typedef H Head;
   typedef T Tail;
};

template<typename T, typename TList> struct exists;

template<typename T, typename Tail> 
struct exists<T, typelist<T, Tail> >
{
    static const bool value = true;
};

template<typename T, typename Head, typename Tail> 
struct exists<T, typelist<Head, Tail> >
{
    static const bool value = false || exists<T, Tail>::value;
};

template<typename T> 
struct exists<T, null_type >
{
    static const bool value = false;
};

template<bool>
struct compile_time_error;

template<>
struct compile_time_error<true> {};

-

Теперь следует код тестирования:

//////////////////////////////////////////////////////////////
//usage

typedef typelist<int> t1;
typedef typelist<short, t1> t2;
typedef typelist<char, t2> t3;
typedef typelist<unsigned char, t3> t4;

typedef t4 supported_types;//supported_types: int, short, char, unsigned char

template<typename T>
struct X
{
    compile_time_error<exists<T,supported_types>::value> unsupported_type_used;
};

int main() {

 //testing if exists<> work or not!
 cout <<(exists<int,supported_types>::value)<< endl;        //should print 1
 cout <<(exists<unsigned int,supported_types>::value)<<endl;//should print 0
 cout <<(exists<char,supported_types>::value)<< endl;       //should print 1
 cout <<(exists<long,supported_types>::value)<< endl;       //should print 0

 X<int> x1;   //okay - int is supported!
 //X<long> x2;  //error - long is unsupported! 
 return 0;
}

, который прекрасно компилируется ( ideone ) и выдает следующее (для операторов cout):

1
0
1
0

Но если вы раскомментируете строку X<long> x2; в приведенном выше коде, она не будет компилироваться, поскольку long является неподдерживаемым типом. И это дает эту ошибку, которую легко читать и понимать ( ideone ):

prog.cpp: в экземпляре X:
prog.cpp: 68: создан здесь
prog.cpp: 56: ошибка: «X :: unsupported_type_used» имеет неполный тип
prog.cpp: 38: ошибка: объявление "struct compile_time_error"

Надеюсь, это поможет вам.


Теперь вы можете написать шаблон класса с именем enable_if_supported, который принимает два аргумента типа: T и supported_types. Вы можете получить свой класс от enable_if_supported как:

template<typename T>
struct X : enable_if_supported<T, supported_types>
{
   //your code
};

Это выглядит немного чисто. enable_if_supported шаблон класса теперь определен в разделе фреймворка. Смотрите здесь, работая: http://www.ideone.com/EuOgc

1 голос
/ 16 июня 2011

Еще один способ:

#include <string>

template <typename T>
struct good_type;

template <> struct good_type< std::string > {typedef char value;};
template <> struct good_type< int > {typedef char value;};

template < typename T >
struct X
{
  typedef typename good_type< T >::value valid;
};

int main(int argc, char** argv)
{
  X< std::string > x1;
  X< int > x2;
  X<float> x3;
}

выдаст:

main.cpp: In instantiation of ‘X<float>’:
main.cpp:19:12:   instantiated from here
main.cpp:12:42: error: invalid use of incomplete type ‘struct good_type<float>’
main.cpp:4:8: error: declaration of ‘struct good_type<float>’

, и вы можете создать макрос для определения допустимых типов:

#define VALID( x ) template <> struct good_type< x > {typedef char value;}

VALID( std::string );
VALID( int );
1 голос
/ 16 июня 2011

Как насчет этого:

#include <string>

template <typename T>
struct good_type;

template <>
struct good_type< std::string > {};

template <>
struct good_type< int > {};

template < typename T >
struct X
{
  good_type< T > someVar;
};

int main(int argc, char** argv)
{
  X< std::string > x1;
  X< int > x2;
  X<float> x3;
}

производит:

main.cpp: In instantiation of ‘X<float>’:
main.cpp:22:12:   instantiated from here
main.cpp:15:18: error: ‘X<T>::someVar’ has incomplete type
main.cpp:4:8: error: declaration of ‘struct good_type<float>’
0 голосов
/ 17 июня 2011

BOOST_MPL_ASSERT создает лучшие сообщения: http://ideone.com/BR0GJ

prog.cpp: In instantiation of ‘X<float>’:
prog.cpp:24:   instantiated from here
prog.cpp:17: error: no matching function for call to 
  ‘assertion_failed(mpl_::failed************ good_type<float>::************)’
prog.cpp: In function ‘int main(int, char**)’:
prog.cpp:22: warning: unused variable ‘x1’
prog.cpp:23: warning: unused variable ‘x2’
prog.cpp:24: warning: unused variable ‘x3’
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...