c++ - 无法为元组重载模板化运算符,但可以为自定义类型重载

标签 c++ templates c++11 overloading

我有以下代码:

// 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 中声明,而它的参数属于命名空间 Mstd,这意味着编译器将查找这些命名空间和封闭的(全局)命名空间。如果你把它移到其中一个,它就会起作用。例如,在 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/

相关文章:

c++ - 模板化派生类的特化函数模板

HTML 模板对齐

c++ - 我的树节点缺少链接

c++ - 在两个函数中使用相同的变量

c++ - 为什么在某些 STL 容器中我们不能直接使用 lambda 而不提及它的类型?

c++ - 如何干净地创建类型安全的枚举参数

C++11:对 const、volatile、左值引用和右值引用限定的成员函数指针进行抽象?

C++重载静态常量字符串与字符数组

c++ - 逐列比较

包含 return 的 C++ 宏表达式(就像 Rust 的 try!)