I was writing a small library in C++ where I only want the template to be instantiated if it is templated on an arithmetic type and I found the following issue:
If I have the following definition of Foo
:
template<typename T, typename Enable = void>
class Foo;
template<typename T>
class Foo<T, std::enable_if<std::is_arithmetic<T>::value>::type> {
Foo() = default;
Foo( const Foo& ) = default;
~Foo() = default;
template<typename U>
Foo( std::initializer_list<U> list )
{
static_assert(std::is_convertible<U, T>::value, "Must use an initializer list with type convertible to T");
for( std::size_t s = 0; s < 10; ++s )
{
tArray[s] = static_cast<U>(list[s]);
}
}
private:
T tArray[10];
};
And I try to initialize it as follows:
int main()
{
Foo<int> test{ {1, 2, 3, 4, 5, 6, 7, 8, 9, 10} };
return 0;
}
I get the following error:
Foo<T, std::enable_if<std::is_arithmetic<T>::value>::type>::Foo( std::initializer_list<U> )
[withT=int
,U=int
] is inaccessible
I'm new to using std::enable_if
in TMP, but according to cppreference.com it appears that this should work. What is it that I'm missing here, or is this a bug with VS2013?
Your initializer is declared as private. Declare it as public. And don't forget to add typename
when using std::enable_if<>::type
.
Edit: There is no subscript overloading in std::initializer_list
.
template<typename T, typename Enable = void>
class Foo;
template<typename T>
class Foo<T, typename std::enable_if<std::is_arithmetic<T>::value>::type> {
public:
Foo() = default;
Foo( const Foo& ) = default;
~Foo() = default;
template<typename U>
Foo( std::initializer_list<U> list )
{
static_assert(std::is_convertible<U, T>::value, "Must use an initializer list with type convertible to T");
for( std::size_t s = 0; s < 10; ++s )
{
// ERROR
// tArray[s] = static_cast<U>(list[s]);
}
}
private:
T tArray[10];
};