Reputation: 51565
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_> >]
Upvotes: 2
Views: 3650
Reputation: 2196
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);
Upvotes: 6
Reputation: 208456
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.
Upvotes: 3