以下是我正在尝试做的一个简要示例:
#include <string>
#include <iostream>
#include <type_traits>
template <typename T>
class foo
{
public:
template <typename U>
typename std::enable_if<std::is_same<T, U>::value>::type
bar(const U& t)
{
std::cout << t << "\n";
}
};
template <typename... Args>
class baz
: public foo<Args>...
{
};
int main()
{
baz<double, std::string> b;
b.bar(1.0);
}
这给了我模糊的功能错误:
error: request for member 'bar' is ambiguous b.bar(1.0); note: candidates are: template<class U> typename std::enable_if<std::is_same<T, U>::value>::type foo<T>::bar(const U&) [with U = U; T = std::basic_string<char>] note: template<class U> typename std::enable_if<std::is_same<T, U>::value>::type foo<T>::bar(const U&) [with U = U; T = double]
我的问题有两个:
U
没有推断出来?我认为这是由于模板扣除和重载解析的排序,但有人可以解释一下吗?答案 0 :(得分:5)
我认为错误信息具有误导性。问题实际上名称bar
在多个基类中可用,并且您不使用using
指令将您想要的名称带入派生类范围。
这是一个有效的解决方案:
template <typename X, typename... Args>
class baz : public foo<X>, public baz<Args...>
{
public:
using foo<X>::bar; //bring the name from the first base
using baz<Args...>::bar; //bring the name from the second base
};
template <typename X>
class baz<X> : public foo<X> //specialization for one argument
{
//no using directive needed, as there is one base only!
};
答案 1 :(得分:4)
该问题与可变参数模板,模板参数推导等无关。这是来自不同基类的同名成员函数不会重载。最小化的例子:
struct foo {
void f(int &);
};
struct bar {
void f(const int &);
};
struct foobar : foo, bar { };
int main(){
foobar fb;
int i;
fb.f(i); // clang complains: error: member 'f' found in multiple base classes of different types
}
由于在您的代码中,foo<double>
和foo<std::string>
是不同的类型,而bar
的查找在每个代码中都找到了声明,因此您的代码格式不正确。
可能的解决方法是编写一个明确分派给相应baz::bar
的{{1}}:
foo::bar
如果需要,您可以template <typename... Args>
class baz
: public foo<Args>...
{
public:
template <typename U>
void
bar(const U& t)
{
foo<U>::bar(t);
}
};
上baz::bar
上的SFINAE U
作为Args
中的某种类型。
另一种可能的解决方案是使用Nawaz's answer中显示的递归实现。