I'm trying to trigger a compile time error if the user of my library tries to instantiate a template with a type that is not appropriate. I've implemented:
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;
}
which works, but the message I get from gcc is a bit surprising:
error: invalid application of 'sizeof' to incomplete type 'boost::STATIC_ASSERTION_FAILURE<false>'
Should I be using a different Boost macro? Is there a better way to do this?
Thanks!
You can use boost::enable_if
, along with typelist.
Define a typelist which contains all the types which you want to support, and write some metafunction(s), to check if a given type exists in the list or not, and then pass the value which metafunction returns to enable_if
, so as to enable/disable the class.
Alright, I wrote a code for demo. Its not using boost::enable_if
though (that is for you to experiment with).
Here is the framework first:
////////////////////////////////////////////////////////////
//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> {};
--
Now follows the testing code:
//////////////////////////////////////////////////////////////
//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;
}
which compiles perfectly fine (ideone), and gives this output (for the cout
statements):
1
0
1
0
But if you uncomment the line X<long> x2;
in the above code, it will not compile, since long
is an unsupported type. And it gives this error, which is easy to read and understand (ideone):
prog.cpp: In instantiation of ‘X’:
prog.cpp:68: instantiated from here
prog.cpp:56: error: ‘X::unsupported_type_used’ has incomplete type
prog.cpp:38: error: declaration of ‘struct compile_time_error’
Hope this helps you.
Now you can write a class template called enable_if_supported
which takes two type arguments: T
and supported_types
. You can derive your class from enable_if_supported
as:
template<typename T>
struct X : enable_if_supported<T, supported_types>
{
//your code
};
This looks a bit clean. enable_if_supported
class template now is defined in the framework section. See it here working : http://www.ideone.com/EuOgc
How about this :
#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;
}
produces :
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>’
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With