无法为元组重载模板化运算符,但可以为自定义类型重载
Unable to overload templated operator for tuple but ok for custom type
我有以下代码:
// 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();
这一切都是关于重载 >>
运算符以便能够读取向量(这是简化的代码,但它已足够完整以显示问题)。
以上代码将按预期编译和工作,但如果我取消注释 B.cpp
中的注释行并注释下面的行:
std::vector<std::tuple<int, double>> v2;
// std::vector<Y> v2;
它没有编译,因为找不到 std::tuple<int, double>
的 operator>>
重载,它尝试调用模板化方法,当然编译失败 t = static_cast<T>(0)
.
我认为编译器可能无法在 std::tuple<int, double>
的两个声明之间创建 link 所以我尝试使用 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;
}
}
我不知道为什么允许在 third-party 命名空间中声明运算符,可以这么说,首先。
我有以下代码:
// 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();
这一切都是关于重载 >>
运算符以便能够读取向量(这是简化的代码,但它已足够完整以显示问题)。
以上代码将按预期编译和工作,但如果我取消注释 B.cpp
中的注释行并注释下面的行:
std::vector<std::tuple<int, double>> v2;
// std::vector<Y> v2;
它没有编译,因为找不到 std::tuple<int, double>
的 operator>>
重载,它尝试调用模板化方法,当然编译失败 t = static_cast<T>(0)
.
我认为编译器可能无法在 std::tuple<int, double>
的两个声明之间创建 link 所以我尝试使用 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;
}
}
我不知道为什么允许在 third-party 命名空间中声明运算符,可以这么说,首先。