Suppose I have this variadic base class-template:
template <typename ... Types>
class Base
{
public:
// The member foo() can only be called when its template
// parameter is contained within the Types ... pack.
template <typename T>
typename std::enable_if<Contains<T, Types ...>::value>::type
foo() {
std::cout << "Base::foo()\n";
}
};
The foo()
member can only be called when its template-parameter matches at least one of the parameters of Base
(the implementation of Contains
is listed at the bottom at this post):
Base<int, char>().foo<int>(); // fine
Base<int, char>().foo<void>(); // error
Now I define a derived class that inherits twice from Base, using non-overlapping sets of types:
struct Derived: public Base<int, char>,
public Base<double, void>
{};
I was hoping that when calling e.g.
Derived().foo<int>();
the compiler would figure out which base-class to use, because it is SFINAE'd out of the one that does not contain int
. However, both GCC 4.9 and Clang 3.5 complain about an ambiguous call.
My question then is two-fold:
- Why can't the compiler resolve this ambiguity (general interest)?
- What can I do to make this work, without having to write
Derived().Base<int, char>::foo<int>();
? EDIT: GuyGreer showed me that the call is disambiguated when I add two using-declarations. However, since I'm providing the base-class for the user to inherit from, this isn't an ideal solution. If at all possible, I don't want my users to have to add those declarations (which can be quite verbose and repetitive for large type-lists) to their derived classes.
Implementation of Contains
:
template <typename T, typename ... Pack>
struct Contains;
template <typename T>
struct Contains<T>: public std::false_type
{};
template <typename T, typename ... Pack>
struct Contains<T, T, Pack ...>: public std::true_type
{};
template <typename T, typename U, typename ... Pack>
struct Contains<T, U, Pack ...>: public Contains<T, Pack...>
{};