我有以下代码:
// A.hpp
#include <vector>
namespace M {
struct A {
template <typename T>
A& operator>> (std::vector<T> &t) {
for (int i = 0; i < 4; ++i) {
t.push_back(T());
*this >> t.back();
}
return *this;
}
template <typename T>
A& operator>> (T &t) {
long long int v = 0;
t = static_cast<T>(v);
return *this;
}
};
}
// B.hpp
#include "A.hpp"
#include <tuple>
namespace N {
struct X { };
M::A& operator>> (M::A &b, X &x);
void f ();
}
// B.cpp
#include "B.hpp"
#include <tuple>
#include <vector>
#include <iostream>
namespace N {
M::A& operator>> (M::A &a, std::tuple<int, double> &v) {
return a;
}
struct Y { };
M::A& operator>> (M::A &a, Y &y) {
return a;
}
M::A& operator>> (M::A &a, X &x) {
// std::vector<std::tuple<int, double>> v2;
std::vector<Y> v2;
a >> v2;
return a;
}
void f () {
M::A a;
X x;
a >> x;
}
}
要运行上面的代码,我只需执行以下操作:
N::f();
这都是关于重载 >>
运算符能够读取 vector (这是简化的代码,但它足够完整以显示问题)。
上面的代码将按预期编译和工作,但如果我取消注释 B.cpp
中的注释行并注释下面的行:
std::vector<std::tuple<int, double>> v2;
// std::vector<Y> v2;
它不编译因为operator>>
的重载对于 std::tuple<int, double>
未找到并尝试调用模板化方法,当然无法编译 t = static_cast<T>(0)
.
我认为编译器可能无法在 std::tuple<int, double>
的两个声明之间建立链接所以我尝试了 typedef
但它没有任何改变。
为什么可以重载 >>
自定义类型的运算符(例如 Y
)但不是标准的 std::tuple
?有没有办法重载 std::tuple
的函数? ?
旁注:这是一个相当复杂的 MVCE,但如果我将所有内容都放在一个文件中,我将无法重现问题...如果您提出一个更小的示例,请随意编辑。
最佳答案
我对标准的了解有点模糊,所以如果我的某些假设有误,请纠正我。
编译器似乎在参数所属的命名空间(首选)和封闭的命名空间中寻找运算符。
M::A& operator>> (M::A &a, Y &y) {
return a;
}
此运算符在与 Y
结构相同的命名空间中声明,因此它可以工作。
M::A& operator>> (M::A &a, std::tuple<int, double> &v) {
return a;
}
这个在命名空间 N
中声明,而它的参数属于命名空间 M
和 std
,这意味着编译器将查找这些命名空间和封闭的(全局)命名空间。如果你把它移到其中一个,它就会起作用。例如,在 B.cpp 中:
namespace M {
M::A& operator>> (M::A &a, std::tuple<int, double> &v) {
std::cout << "special call T" << std::endl;
return a;
}
}
我不知道为什么允许在第三方命名空间中声明运算符,可以说,首先。
关于c++ - 无法为元组重载模板化运算符,但可以为自定义类型重载,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34853014/