简体   繁体   中英

C++ namespace ambiguity

I have both ::tensor::contract and ::tensor::detail::contract

#include "tensor/detail/contract.hpp"

namespace tensor {


    template<typename Alpha, class A, class B, typename Beta, class C>
    void contract(Alpha alpha, A a, B b, Beta beta, C c) {
        detail::contract(alpha, a, b, beta, c);
    }

    template<class A, class B, typename U = int>
    struct contract_expression :
        expression<contract_expression<A,B,U> >
    {
        template<typename T, class C>
        void evaluate(T alpha, T beta, expression<C> &c) const {
            contract(alpha*alpha_, a, b, beta, c); // ambiguity here
        };
    };

why do I get ambiguity in contract_expression::evaluate ? I am fairly certain there is no stray using directive.

error:

 ../../src/tensor/contract.hpp:12: note: candidates are: void tensor::contract(Alpha, A, B, Beta, C) [with Alpha = int, A = tensor::tensor_view<boost::detail::multi_array::multi_array_view<d\
ouble, 2u>, boost::fusion::map<tensor::index<98, tensor::detail::index_range>, tensor::index<97, tensor::detail::index_range>, boost::fusion::void_, boost::fusion::void_, boost::fusion::voi\
d_, boost::fusion::void_, boost::fusion::void_, boost::fusion::void_, boost::fusion::void_, boost::fusion::void_> >, B = tensor::tensor_view<boost::detail::multi_array::multi_array_view<dou\
ble, 3ul>, boost::fusion::map<tensor::index<97, tensor::detail::index_range>, tensor::index<99, tensor::detail::index_range>, tensor::index<100, tensor::detail::index_range>, boost::fusion:\
:void_, boost::fusion::void_, boost::fusion::void_, boost::fusion::void_, boost::fusion::void_, boost::fusion::void_, boost::fusion::void_> >, Beta = int, C = tensor::tensor_view<boost::det\
ail::multi_array::multi_array_view<double, 3ul>, boost::fusion::map<tensor::index<98, tensor::detail::index_range>, tensor::index<99, tensor::detail::index_range>, tensor::index<100, tensor\
::detail::index_range>, boost::fusion::void_, boost::fusion::void_, boost::fusion::void_, boost::fusion::void_, boost::fusion::void_, boost::fusion::void_, boost::fusion::void_> >]
../../src/tensor/detail/contract.hpp:109: note:                 void tensor::detail::contract(Alpha, A, B, Beta, C) [with Alpha = int, A = tensor::tensor_view<boost::detail::multi_array::mu\
lti_array_view<double, 2u>, boost::fusion::map<tensor::index<98, tensor::detail::index_range>, tensor::index<97, tensor::detail::index_range>, boost::fusion::void_, boost::fusion::void_, bo\
ost::fusion::void_, boost::fusion::void_, boost::fusion::void_, boost::fusion::void_, boost::fusion::void_, boost::fusion::void_> >, B = tensor::tensor_view<boost::detail::multi_array::mult\
i_array_view<double, 3ul>, boost::fusion::map<tensor::index<97, tensor::detail::index_range>, tensor::index<99, tensor::detail::index_range>, tensor::index<100, tensor::detail::index_range>\
, boost::fusion::void_, boost::fusion::void_, boost::fusion::void_, boost::fusion::void_, boost::fusion::void_, boost::fusion::void_, boost::fusion::void_> >, Beta = int, C = tensor::tensor\
_view<boost::detail::multi_array::multi_array_view<double, 3ul>, boost::fusion::map<tensor::index<98, tensor::detail::index_range>, tensor::index<99, tensor::detail::index_range>, tensor::i\
ndex<100, tensor::detail::index_range>, boost::fusion::void_, boost::fusion::void_, boost::fusion::void_, boost::fusion::void_, boost::fusion::void_, boost::fusion::void_, boost::fusion::vo\
id_> >]

Through ADL , associated namespaces are considered when resolving an unqualified function call. At least one of the parameters on that line is associated with the detail namespace.

ok, i see. does it matter if those types inherit from detail classes? – aaa

Yes, base classes are associated classes for the purposes of name lookup. Functions in the namespaces of base classes are considered (§3.4.2/2, second bullet point).

If you want to force ::tensor::contract to be used, don't use an unqualified name:

::tensor::contract(alpha * alpha_, a, b, beta, c);

Or wrap the function name in parentheses, which disables ADL:

(contract)(alpha * alpha_, a, b, beta, c);

Candidate number one there would be ADL (Argument Dependent Lookup, or Koening's lookup). Without seeing how those templates are instantiated it is hard to tell, but for the sake of argument, if one of the arguments to your function happens to be from within the detail namespace, then that namespace will be added to the lookup.

This is similar to something that you may be well used to:

namespace test {
   struct X {};
   std::ostream& operator<<( std::ostream&, X const & ) {}
}
int main() {
   test::X x;
   std::cout << x; // [1]
}

At the line marked with [1], the code is in the global namespace, and yet it finds operator<< inside the test namespace. The reason is that x is an argument to that call, and the type is test::X , so the compiler looks up the test namespace.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM