1
votes

I am working on a library that makes extensive use of C++ templates. While writing I came to situation with code like this (of course simplified):

#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;
}

While compiling it with msvc 19 (Visual Studio 2017) I get following class of errors:

/opt/compiler-explorer/windows/19.10.25017/lib/native/include/xlocale(314): warning C4530: C++ exception handler used, but unwind semantics are not enabled. Specify /EHsc (28): error C2228: left of '.take' must have class/struct/union (28): note: type is ''

/opt/compiler-explorer/windows/19.10.25017/lib/native/include/xstring(2923): note: see reference to function template instantiation 'auto ns::operator |(A,B)' being compiled with [ A=unsigned int, B= ] /opt/compiler-explorer/windows/19.10.25017/lib/native/include/xstring(2922): note: while compiling class template member function 'void std::basic_string,std::allocator>::shrink_to_fit(void)'

/opt/compiler-explorer/windows/19.10.25017/lib/native/include/system_error(658): note: see reference to function template instantiation 'void std::basic_string,std::allocator>::shrink_to_fit(void)' being compiled

/opt/compiler-explorer/windows/19.10.25017/lib/native/include/stdexcept(22): note: see reference to class template instantiation 'std::basic_string,std::allocator>' being compiled

Removing using namespace works, but I do not want to forbid it (why should I?). Is there a solution?

EDIT: Of course I tested code with GCC and Clang - compiles under GCC from 4.9 and clang3 so it is solely MSVC issue.

EDIT2: I took a look at the reported errors and it seems like MSVC is extending the scope of overloaded operator| inside its standard library when using using namespace.

1
A) If it doesn't compile, maybe you aren't asking about optimization? B) Maybe you want to post the actual error messages?Mats Petersson
Sorry, edited comment, `couse made a mistake.bartop
Just looked at your code on godbolt and you have missed off the 1st error message, please include it in your post.Richard Critten

1 Answers

1
votes

It works this way, but i can't explain why it doesn't work original way, hope it will help somebody else.

Though my guess is that your template is too broad and it gets intantiated by some code from std library. Actually your code also works if your just comment out any std headers or remove 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);
    }
}