运算符|的MSVC错误

时间:2018-02-03 12:51:05

标签: c++ templates visual-c++

我正在开发一个广泛使用C ++模板的库。在写作时,我遇到了这样的代码(当然是简化的):

#include <sstream>

namespace ns{
    template<class A, class B>
    class c{};

    class a{};

    template<class A>
    class b{
    public:
        template<class B>
        auto
        take(A, B){
            return c<A, B>{};
        }
    };

    template<class A>
    auto
    make_b(A){
        return b<A>{};
    }

    template<class A, class B>
    auto
    operator|(A _a, B _b){
        return _b.take(_a, _b);
    }

}

using namespace ns;

int main(){
    a{} | make_b(a{});
    return 0;
}

使用msvc 19(Visual Studio 2017)进行编译时,我会遇到以下错误:

  

/opt/compiler-explorer/windows/19.10.25017/lib/native/include/xlocale(314):warning C4530:使用了C ++异常处理程序,但未启用展开语义。指定/ EHsc   (28):错误C2228:'.take'的左边必须有class / struct / union   (28):注意:类型是''

     

/opt/compiler-explorer/windows/19.10.25017/lib/native/include/xstring(2923):注意:请参阅正在编译的函数模板实例化'auto ns :: operator |(A,B)'的引用           同           [               A = unsigned int,               B =           ]   /opt/compiler-explorer/windows/19.10.25017/lib/native/include/xstring(2922):注意:编译类模板成员函数时'void std :: basic_string,std :: allocator&gt; :: shrink_to_fit(void) “

     

/opt/compiler-explorer/windows/19.10.25017/lib/native/include/system_error(658):注意:请参阅函数模板实例化'void std :: basic_string,std :: allocator&gt; :: shrink_to_fit (void)'正在编译

     

/opt/compiler-explorer/windows/19.10.25017/lib/native/include/stdexcept(22):注意:请参阅类模板实例化'std :: basic_string,std :: allocator&gt;'正在编制

删除using namespace有效,但我不想禁止它(我为什么要这样做?)。有解决方案吗?

编辑:当然我用GCC和Clang测试代码 - 在4.9和clang3的GCC下编译,所以它只是MSVC问题。

EDIT2:我看了一下报告的错误,看起来MSVC在使用operator|时会在其标准库中扩展重载using namespace的范围。

1 个答案:

答案 0 :(得分:1)

它以这种方式工作,但我无法解释为什么它不能以原始方式工作,希望它能帮助其他人。

虽然我的猜测是你的模板太宽并且它会被std库中的一些代码实例化。实际上,如果您只是注释掉任何标准标题或删除using namespace ns,那么您的代码也会有用。

namespace ns {
    template<class A, class B>
    class c {};

    class a {};

    template<class A>
    class b {
    public:
        using MyA = A;
        template<class B>
        auto
            take(A, B) {
            return c<A, B>{};
        }
    };

    template<class A>
    auto
        make_b(A) {
        return b<A>{};
    }

    template<class B>
    auto
        operator|(typename B::MyA _a, B _b) {
        return _b.take(_a, _b);
    }
}