这个(人为的)代码:
#include <iostream>
template<typename T> class Foo
{
public:
Foo(int i) : i_(i) {}
private:
int i_;
};
template<typename T>
Foo<T> bar(const T& /*x*/, const Foo<T>& /*foo*/)
{
std::cout << "first bar()" << std::endl;
return Foo<T>(1);
}
template<typename T>
Foo<T> bar(int /*x*/, const Foo<T>& /*foo*/)
{
std::cout << "second bar()" << std::endl;
return Foo<T>(42);
}
int main()
{
Foo<bool> f1(0);
Foo<bool> f2 = bar(true, f1); // first bar()
Foo<bool> f3 = bar(10, f1); // second bar()
(void)f2; // avoid warning for unused variable
(void)f3; // avoid warning for unused variable
return 0;
}
做得不多,但用g ++ 4.7.2编译好:
$ g++ -std=c++11 -Wall -Wextra foo.cpp
并产生预期结果:
$ ./a.out
first bar()
second bar()
当我在bool
中将模板类型从int
更改为main()
时:
int main()
{
Foo<int> f1(0);
Foo<int> f2 = bar(true, f1); // first bar()
Foo<int> f3 = bar(10, f1); // second bar()
(void)f2; // avoid warning for unused variable
(void)f3; // avoid warning for unused variable
return 0;
}
我收到编译错误:
$ g++ -std=c++11 -Wall -Wextra foo.cpp
foo.cpp: In function 'int main()':
foo.cpp:30:29: error: call of overloaded 'bar(int, Foo<int>&)' is ambiguous
foo.cpp:30:29: note: candidates are:
foo.cpp:13:8: note: Foo<T> bar(const T&, const Foo<T>&) [with T = int]
foo.cpp:20:8: note: Foo<T> bar(int, const Foo<T>&) [with T = int]
问题是bar()
的两个版本在这种情况下都会发生冲突,编译器无法决定选择哪个版本。
怎么能解决这个问题?
答案 0 :(得分:1)
标签调度:
struct selector {};
template<typename T>
Foo<T> bar(const T& /*x*/, const Foo<T>& /*foo*/, const selector&)
{
std::cout << "first bar()" << std::endl;
return Foo<T>(1);
}
// call it
bar(1, f1, selector{});
这只是一个例子,假设更多的重载,需要更复杂。
正如Johan正确指出的那样,enable_if仅适用于模板方法。
答案 1 :(得分:1)
您可以使用struct的部分模板特化,例如:
namespace detail
{
template <typename T1, typename T2> struct bar;
template <typename T> struct bar<T, T>
{
Foo<T> operator()() const
{
std::cout << "first bar()" << std::endl;
return Foo<T>(1);
}
};
template <typename T> struct bar<int, T>
{
Foo<T> operator()() const
{
std::cout << "second bar()" << std::endl;
return Foo<T>(42);
}
};
template <> struct bar<int, int>
{
Foo<int> operator()() const
{
std::cout << "third bar()" << std::endl;
return Foo<int>(42);
}
};
}
template<typename T1, typename T2>
Foo<T2> bar(const T1& /*x*/, const Foo<T2>& /*foo*/)
{
return detail::bar<T1, T2>()();
}
用以下方法测试:
int main()
{
Foo<int> f1(0);
Foo<int> f2 = bar<int>(true, f1); // first bar()
Foo<int> f3 = bar(10, f1); // second bar()
(void)f2; // avoid warning for unused variable
(void)f3; // avoid warning for unused variable
return 0;
}
或
int main()
{
Foo<bool> f1(0);
Foo<bool> f2 = bar(true, f1); // first bar()
Foo<bool> f3 = bar(10, f1); // second bar()
(void)f2; // avoid warning for unused variable
(void)f3; // avoid warning for unused variable
return 0;
}
答案 2 :(得分:0)
如果你可以使用参数选择选项,你可以选择你想要使用哪个栏,这可以消除歧义。我希望这可以帮助。
#include <iostream>
template<typename T> class Foo
{
public:
Foo(int i) : i_(i) {}
private:
int i_;
};
template<typename T>
Foo<T> bar(const T& /*x*/, const Foo<T>& /*foo*/,int pick=0)
{
std::cout << "first bar()" << std::endl;
return Foo<T>(1);
}
template<typename T>
Foo<T> bar(int /*x*/, const Foo<T>& /*foo*/,double pick=0)
{
std::cout << "second bar()" << std::endl;
return Foo<T>(42);
}
int main()
{
Foo<bool> f1(0);
Foo<int> f15(0);
Foo<bool> f2 = bar(true, f1); // first bar()
Foo<int> f3 = bar(10, f15,1); // first bar()
Foo<int> f35 = bar(10, f15,1.0); // second bar()
(void)f2; // avoid warning for unused variable
(void)f3; // avoid warning for unused variable
return 0;
}