c++ - Template functions in namespace cause errors -
assume following code:
#include <iostream> template<typename t> struct link { link(t&& val) : val(std::forward<t>(val)) {} t val; }; template<typename t> std::ostream& operator<<(std::ostream& out, const link<t>& link) { out << "link(" << link.val << ")"; return out; } template<typename t> auto makelink(t&& val) -> link<t> { return {std::forward<t>(val)}; } namespace utils { template<typename any> constexpr auto removelinks(const any& any) -> const any& { return any; } template<typename t> constexpr auto removelinks(const link<t>& link) -> decltype(removelinks(link.val)) { return removelinks(link.val); } } /* utils */ int main() { int k = 10; auto link = makelink(makelink(k)); std::cout << link << std::endl; std::cout << utils::removelinks(link) << std::endl; }
for reason can't understand, generates following compilation errors g++-4.8
:
/home/allan/codes/expr.cpp: in instantiation of ‘constexpr decltype (utils::removelinks(link.val)) utils::removelinks(const link<t>&) [with t = int&; decltype (utils::removelinks(link.val)) = const int&]’: /home/allan/codes/expr.cpp:88:32: required ‘constexpr decltype (utils::removelinks(link.val)) utils::removelinks(const link<t>&) [with t = link<int&>; decltype (utils::removelinks(link.val)) = const int&]’ /home/allan/codes/expr.cpp:100:41: required here /home/allan/codes/expr.cpp:88:32: error: invalid initialization of reference of type ‘const link<int&>&’ expression of type ‘const int’ return removelinks(link.val); ^ /home/allan/codes/expr.cpp:89:1: error: body of constexpr function ‘constexpr decltype (utils::removelinks(link.val)) utils::removelinks(const link<t>&) [with t = int&; decltype (utils::removelinks(link.val)) = const link<int&>&]’ not return-statement } ^ /home/allan/codes/expr.cpp: in function ‘constexpr decltype (utils::removelinks(link.val)) utils::removelinks(const link<t>&) [with t = int&; decltype (utils::removelinks(link.val)) = const int&]’: /home/allan/codes/expr.cpp:89:1: warning: control reaches end of non-void function [-wreturn-type] } ^
while clang 3.3 gives:
test.cc:34:12: error: reference type 'const link<int &>' not bind lvalue of type 'const int' return removelinks(link.val); ^~~~~~~~~~~~~~~~~~~~~ test.cc:46:25: note: in instantiation of function template specialization 'utils::removelinks<link<int &> >' requested here std::cout << utils::removelinks(link) << std::endl;
if, however, namespace utils
removed, compiles without errors (both gcc , clang), , execution outputs:
link(link(10)) 10
why defining template functions (removelinks
) in namespace causes such errors?
this problem result of issue point of declaration (1) combined dependent name lookup (2).
(1) in declaration
template<typename t> constexpr auto removelinks(const link<t>& link) -> decltype(removelinks(link.val))
the name removelinks
, or more precisely, overload of removelinks
, visible after complete declarator according [basic.scope.pdecl]/1. trailing-return-type part of declarator per [dcl.decl]/4. see this answer.
(2) in expression removelinks(link.val)
, name removelinks
dependent per [temp.dep]/1, link.val
dependent.
if how dependent names resolved, find [temp.dep.res]:
in resolving dependent names, names following sources considered:
- declarations visible @ point of definition of template.
- declarations namespaces associated types of function arguments both instantiation context , definition context.
the first bullet doesn't find second overload of removelinks
because of point of declaration (1). second 1 doesn't find overload because namespace util
not associated argument. why putting in global namespace or in namespace util
works expected (live example).
for same reason, using qualified-id in trailing-return-type (like -> decltype(util::removelinks(link.val))
doesn't here.
Comments
Post a Comment