Sign in to follow this  
matt77hias

Restricting class template argument to PODs

Recommended Posts

I use the following code for restricting a class template argument to be a Plain Old Data type:

template< typename T, typename Enable = void >
struct Vector2;

template< typename T >
struct Vector2< T, typename std::enable_if< std::is_pod< T >::value, void >::type> {

// ...

}

I understand the std::enable_if construct, but I do not understand why I need the "first Vector2" declaration. Of course if I hadn't this one, I couldn't do things like:

using F32x2 = Vector2< F32 >;

But what is the magic behind: typename Enable = void and how is this connected to the "second Vector2" declaration?

Edited by matt77hias

Share this post


Link to post
Share on other sites

What you are doing is called SFINEA. Theres not that much magic going on:

The first declaration of Vector2 is the actual declaration of Vector2. "typename Enable = void" is just a regular template parameter with a default value of "void" (which is there so you can use Vector2 with only one argument). The second declaration is actually a spezialisation of the first (lookup template spezialisation when you are unsure about that), and due to SFINEA rules and how std::enable_if works, it will only be available when std::is_pod is actually satisfied - for all other types, it will select the unspecialized declaration #1. Thats all there is to it :)

Actually, I'd personally just use one vector-declaration, and use a static-assert instead:

template<typename Type>
struct Vector2
  {
  	static_assert(std::is_pod_v<Type>, "Type must be pod.");
  };

Almost same effect, easier to understand code, and easier-to-understand error reporting, IMHO. Also, wouldn't you want to check for std::is_arithmetic instead, or do you specifically want to support custom-POD structs as well? :)

Share this post


Link to post
Share on other sites
17 minutes ago, Juliean said:

Almost same effect, easier to understand code, and easier-to-understand error reporting, IMHO. Also, wouldn't you want to check for std::is_arithmetic instead, or do you specifically want to support custom-POD structs as well? :)

That one is idd. a better choice for my purposes.

Thanks for the clear explanation!

Share this post


Link to post
Share on other sites
24 minutes ago, Juliean said:

and use a static-assert instead:

It depends, if you still want to allow to define a different specialization, you need the std::enable_if.

Otherwise, both will work. But you're right that in this case the static_assert is more concise and clearer. On the other hand changing the template seems easier to document with some tool such as Doxygen.

29 minutes ago, Juliean said:

What you are doing is called SFINEA.

Does this required some changes to the C++98 compiler to support this?

Share this post


Link to post
Share on other sites
2 hours ago, matt77hias said:

It depends, if you still want to allow to define a different specialization, you need the std::enable_if.

If you want to specialize based on a another range of types, sure, for specialization based on single types you wouldn't need it though:

template<typename Type>
struct Vector2
{
};
  
template<>
struct Vector2<double>
{
};

So unless you actually know what different set of types you'd want to specialize against, I'd put it under YAGNI, and stick with the solution that fits more right now.

2 hours ago, matt77hias said:

Does this required some changes to the C++98 compiler to support this?

Cannot really answer that. Expression-SFINEA certainly required a compiler-change from what I can tell, but as for the older parts of SFINEA, I cannot tell.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this