I'm looking for a solution to a following problem:
#include <string>
class A
{
public:
template <typename T>
static typename std::enable_if<std::is_same<T, std::string>::value, void>::type foo(T val)
{
printf("std::string\n");
}
template<typename T, typename... Arg>
static void multiple(Arg&&... arg)
{
T::foo(arg...);
}
};
class B : public A
{
public:
template <typename T>
static typename std::enable_if<std::is_same<T, int>::value, void>::type foo(T val)
{
printf("int\n");
}
};
int main()
{
std::string a;
int b = 0;
A::multiple<B>(a, b);
}
All works fine if both foo
methods are in the same class or I force foo
from proper class (A::foo
for std::string
and B::foo
for int
), however I need more than one class, because base class must be extendable. I can't use simple specialization, because I need more SFINAE features like detect for std::pair
, std::tuple
etc. I also don't want to move foo methods from a class to a namespace. Do you have any Idea how can I solve this issue?
Here B::foo
hides A::foo
, you need a using
:
class B : public A
{
public:
using A::foo;
template <typename T>
static typename std::enable_if<std::is_same<T, int>::value, void>::type foo(T val)
{
printf("int\n");
}
};
But
From namespace.udecl#15.sentence-1:
When a using-declarator brings declarations from a base class into a derived class, member functions and member function templates in the derived class override and/or hide member functions and member function templates with the same name, parameter-type-list, cv-qualification, and ref-qualifier (if any) in a base class (rather than conflicting)
Return type doesn't count, so you have to use std::enable_if
in parameter:
class A
{
public:
template <typename T>
static void foo(T val, std::enable_if_t<std::is_same<T, std::string>::value, int> = 0)
{
printf("std::string\n");
}
};
class B : public A
{
public:
using A::foo;
template <typename T>
static void foo(T val, std::enable_if_t<std::is_same<T, int>::value, int> = 0)
{
printf("int\n");
}
};
Note: you also have typo for
template<typename T, typename... Arg>
static void multiple(Arg&&... arg)
{
T::foo(arg...); // B::foo(string, int)
}
which should be
template<typename T, typename... Arg>
static void multiple(Arg&&... arg)
{
(T::foo(arg), ...); // B::foo(string), B::foo(int)
}