I want to specialize a template class constructor:
If type is int default value is 50 and -50. and if it's float default should be 0.5 and -0.5 .
My code is :
#include <iostream>
#include <limits>
#include <type_traits>
template<typename T>
class Foo{
public:
template<typename = typename std::enable_if<
std::is_integral<T>::value&& !std::is_floating_point<T>::value>::type>
Foo(T value1 = 50, T value2 = -50) :value1_(value1), value2_(value2){}
template<typename = typename std::enable_if<
std::is_floating_point<T>::value>::type>
Foo(T value1 = 0.5, T value2 = -0.5, void* dummy = 0) : value1_(value1), value2_(value2){}
T value1_, value2_;
};
int main()
{
Foo<float> test;
std::cout << test.value1_ << " " << test.value2_ << '\n';
Foo<int> test2;
std::cout << test2.value1_ << " " << test2.value2_;
}
It works just fine in visual studio 2013 .
But gcc 4.9.2 rejects it :
main.cpp: In instantiation of 'class Foo<float>':
main.cpp:29:13: required from here
main.cpp:19:3: error: no type named 'type' in 'struct std::enable_if<false, void>'
Foo(T value1 = 50, T value2 = -50) :value1_(value1), value2_(value2){}
^
main.cpp: In instantiation of 'class Foo<int>':
main.cpp:32:11: required from here
main.cpp:23:3: error: no type named 'type' in 'struct std::enable_if<false, void>'
Foo(T value1 = 0.5, T value2 = -0.5, void* dummy = 0) : value1_(value1), value2_(value2){}
^
Is my code wrong? if so why visual studio compile it ? or maybe it's a gcc bug ?!
Your code is incorrect. The top-level
T
cannot be used in a SFINAE context for its methods, which is what you are trying to do. Only a substitution that takes place in an immediate context may result in a deduction failure (§14.8.2/8):GCC and Clang are correct in rejecting your code.
A workaround is just to introduce a dummy template type that defaults to the top-level
T
, and SFINAE on that one. Like so:Note that
is_integral
andis_floating_point
are mutually exclusive, you should only have to check one or the other.In this example, it'd probably be a lot simpler just to farm out the default values to another struct, so that you can have just one constructor that looks like: