I've tried to boil this down to the essentials.
I have a variadic template class, Foo, containing a "list" of objects indexed with their types. I use the function bar<U>()
to extract the element of that type. I solve this using a variadic template and std::enable_if to only define bar<U>()
where T == U.
Then I expose all "bar" functions from the base classes with "using".
#include <type_traits>
template<typename... Ts>
class Foo
{
public:
void bar() {}
};
template<typename T, typename... Ts>
class Foo<T, Ts...> : public Foo<Ts...>
{
public:
using Foo<Ts...>::bar;
template<typename U>
typename std::enable_if<std::is_same<U, T>::value, U >::type
bar()
{
return mObj;
}
private:
T mObj;
};
template<typename T>
void bar2()
{
Foo<int, float, double> list;
list.bar<T>();
}
int main()
{
bar2<float>();
return 0;
}
This works wonderfully, except on Clang and Visual Studio 2015. Tried both MSVC 19.0 and 19.10, and gives the error:
Compiled with /EHsc /nologo /W4 /c
main.cpp
main.cpp(30): error C2672: 'Foo<int,float,double>::bar': no matching overloaded function found
main.cpp(35): note: see reference to function template instantiation 'void bar2<float>(void)' being compiled
main.cpp(30): error C2770: invalid explicit template argument(s) for 'std::enable_if<std::is_same<U,T>::value,U>::type Foo<int,float,double>::bar(void)'
with
[
T=int
]
main.cpp(18): note: see declaration of 'Foo<int,float,double>::bar'
GCC between at least at least 4.7-6.3 compile this fine. I first thought that this might be to some feature from c++11 missing in Visual Studio 2015, but surprisingly this compiles fine in the older Visual Studio 2013 (MSVC 18.0). Clang also fails.
So my question is, is this a shortcoming of these compilers or is there something I'm doing here that isn't allowed?
If I call "bar" with a hard-coded type like list.bar<int>()
it compiles on all tested compilers.