我有一些非常简化的代码看起来像这样:
#include <iostream>
#include <type_traits>
namespace X {
struct Foo {int x;};
struct Bar {int x;};
template <typename T , typename = typename std::enable_if<
std::is_same<decltype(T::x),int>::value
>::type>
std::ostream & operator<<(std::ostream & os, const T&) {
return os;
}
}
namespace Y {
struct Faa : X::Foo {int y;};
struct Baz {int x; int y;};
template <typename T , typename = typename std::enable_if<
std::is_same<decltype(T::x),int>::value &&
std::is_same<decltype(T::y),int>::value
>::type>
std::ostream & operator<<(std::ostream & os, const T&) {
return os;
}
}
int main() {
// Everything is ok
X::Foo x;
std::cout << x;
Y::Baz k;
std::cout << k;
// Problems..
Y::Faa y;
// std::cout << y; // <--operator is ambiguous
Y::operator<<(std::cout, y);
return 0;
}
有没有办法避免Y::Faa
的模糊运算符并且必须手动指定Y::operator<<
?如果没有,为什么?
答案 0 :(得分:3)
两个函数存在冲突,因为它们的参数上的条件具有非空交集(实际上,第一个取代第二个)。仅当签名不同时,函数重载才起作用。因此,要解决这个问题,我们有两个选择:
更改条件,以便它们具有空交集(通过向{1} y
添加&& !sfinae_has_member_y<T>::value
条件,手动禁止enable_if
字段
template<typename T>
struct sfinae_has_member_y {
static int has(...);
template<typename U = T, typename = decltype(U::y)>
static char has(const U& value);
enum { value = sizeof(char) == sizeof(has(std::declval<T>())) };
};
或者使用支持重叠参数的其他C ++特性,例如 struct / class template specialization 。如果您将bool
替换为int
,则也可以添加其他字段:
template<typename T, bool>
struct Outputter {
};
template<typename T>
struct Outputter<T, false> {
static std::ostream & output(std::ostream & os, const T&) {
os << "x";
return os;
}
};
template<typename T>
struct Outputter<T, true> {
static std::ostream & output(std::ostream & os, const T&) {
os << "y";
return os;
}
};
template<typename T, typename = std::enable_if_t<std::is_same<decltype(T::x), int>::value>>
std::ostream & operator<<(std::ostream & os, const T& a) {
return Outputter<T, sfinae_has_member_y<T>::value>::output(os, a);
}