以下是個人的解釋不知道對不對
spec: N3485
14.6/p9
When looking for the declaration of a name used in a template definition,
...
The lookup of names dependent on the template parameters is
postponed until the actual template argument is known
14.6.2/p1
In an expression of the form:
postfix-expression ( expression-list)
where the postfix-expression is an unqualified-id, the unqualified-id denotes
a dependent name if
— any of the expressions in the expression-list is a pack expansion ,
— any of the expressions in the expression-list is a type-dependent expression,
or
— if the unqualified-id is a template-id in which any of the template
arguments depends on a template parameter.
If an operand of an operator is a type-dependent expression, the operator
also denotes a dependent name. Such names are unbound and are looked up at
the point of the template instantiation (14.6.4.1) in both
the context of the template definition and
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
the context of the point of instantiation.
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
14.6.4.1/p1
For a function template specialization,
...
if the specialization is implicitly instantiated because it is referenced
from within another template specialization and the context from which it is
referenced depends on a template parameter, the point of instantiation of the
specialization is the point of instantiation of the enclosing specialization.
Otherwise, the point of instantiation for such a specialization immediately
follows the namespace scope declaration or definition that refers to the
specialization.
首先 base case定義於general case之後
因此, 不論有沒有加namespace,
想在the context of the template definition中找到base case是不可能的
同時 _set_nth_element的general case永遠找的到自己
所以問題在於 為什麼沒加namespace的時候 就能在
the context of the point of instantiation中找的到base case
以下將point of instantiation簡寫為POI
沒有namespace的時候 apply 14.6.4.1得到
main ->
set_nth_element<7> -> POI在set_nth_element之後
_set_nth_element<0> -> POI在set_nth_element之後
_set_nth_element<1> -> ...
_set_nth_element<7> POI在set_nth_element之後
既然POI在set_nth_element之後 就能找到_set_nth_element的base case
加了namespace之後 雖然POI在set_nth_element之後
但_set_nth_element的general還是無法找到處於detail中的base case
如果在set_nth_element的definition之前加上
using detail::_set_nth_element;
就可以正常編譯了
以上看起來好像很順 但其實有問題
14.6.4.2 Candidate functions [temp.dep.candidate]
For a function call where the postfix-expression is a dependent name, the
candidate functions are found using the usual lookup rules (3.4.1, 3.4.2)
except that:
— For the part of the lookup using unqualified name lookup (3.4.1), only
function declarations from the template definition context are found.
— For the part of the lookup using associated namespaces (3.4.2), only
function declarations found in either the template definition context
or the template instantiation context are found
事實上 要在instantiation context中進行lookup 必須透過Argument Dependent Lookup
那麼
_set_nth_element<CUR_IDX+1>(
p, f,
std::integral_constant<int, LeftDistance::value-1>()
);
的argument中, p是fundamental type沒有associated namespace
std::integral_constant的associated namespace就是std所以也連不到global namespace
f呢?
f是個lambda expression產生的closure object
closure object依照spec來說是個local class 本不應該有associated namespace
所以照理來說原本的程式就算不加namespace detail也不應該能編譯
(因為general case還是應該找不到base case)
應該一番google 看起來似乎是g++的bug:
https://groups.google.com/a/isocpp.org/forum/#!topic/std-proposals/6Mp0OUawJ8M
"It appears that g++ includes the enclosing namespaces as associated
namespaces for local classes, contrary to the current rules in the standard."
所以我把你原本的程式(沒有detail namespace)用clang 3.4.1去編:
http://gcc.godbolt.org/
一樣會有類似的錯誤
note: in instantiation of function template specialization
'_set_nth_element<254, int *, <lambda at
/tmp/gcc-explorer-compiler114631-16727-xtob8u/example.cpp:65:31>,
std::integral_constant<int, -247> >' requested here
請注意上面的254跟-247 一樣代表展開時沒找到base case
以上推導不知道對不對