Why can we not declare a deduction guide outside an inline namespace? - c++

Example:
namespace X{
inline namespace Y{
template<typename T>
struct A{
};
}
}
namespace X{
template<typename Z>
A(std::vector<Z>) -> A<Z>;
}
This causes a compile error in Clang 11, which says "Deduction guide must be declared in the same scope as template X::Y::A"
Similar to the template specialization, the deduction guide should also be declared within the same semantic scope as the class template. So why can I specialize the class template outside the inline namespace, but for a deduction guide I can't?
Especially, this causes another problem:
template<typename T>
struct Q{
operator std::vector<T>() {
return {};
}
};
namespace std{
template<typename T>
vector(Q<T>) -> vector<T>;
}
The compiler refuses if I want to define a class template with a conversion to std::vector and declare a deduction guide for it. In this case (for libc++), I have to declare it in namespace std::__1.
Is there some solution or explanation in the CPP standard?

so why I can specialize the class template outside the inline namespace, but for deduction guide I can't?
Because you are allowed to specialize the template. From C++ standard [namespace.def]/7:
Members of an inline namespace can be used in most respects as though they were members of the enclosing namespace. Specifically, the inline namespace and its enclosing namespace are both added to the set of associated namespaces used in argument-dependent lookup whenever one of them is, and a using-directive that names the inline namespace is implicitly inserted into the enclosing namespace as for an unnamed namespace.
Furthermore, each member of the inline namespace can subsequently be partially specialized, explicitly instantiated, or explicitly specialized as though it were a member of the enclosing namespace
For the deduction guide it needs to be in the same scope as the class template. From the standard [temp.deduct.guide]/3:
[...] A deduction-guide shall be declared in the same scope as the corresponding class template and, for a member class template, with the same access. [...]
Solution would be to explicitly give X::Y scope:
namespace X::inline Y{
template<typename Z>
A(std::vector<Z>) -> A<Z>;
}

The intent behind template specialization is that you can add specializations to a template even if you're not the author of the template. One might do this because they are the author of a type which is being used by this specialization. The C++ standard library's rules forbid adding declarations to the std namespace except for template specializations for precisely this reason.
Deduction guides are not like template specializations. They are considered part of the class template's definition, much like constructors and other member functions. As such, they are expected to be written by the creator of the class, typically immediately following the template class's definition. Given these expectations, it doesn't make sense for deduction guides to exist in a scope other than the scope of the template class definition itself.
Basically, you are not meant to be able to add deduction guides to someone else's class templates.
The very first version of the CTAD proposal, as well as every derivative version thereof, focuses on mapping constructor arguments to class template parameters. What will eventually be known as "deduction guides" were first discussed as "Canonical factory functions". But the text around it is particularly telling:
We suggest a notation to allow constructors to specify their template parameters by either explicitly declaring the signatures for any further needed constructor deductions outside the class
Notice how focused the text is on "constructors". These canonical factory functions are maps between constructors and template arguments. They are considered, conceptually at least, to be constructors of a sort. After all, implicit guides are generated from constructors, so it stands to reason that explicit guides are conceptually equivalent to a class constructor.
Indeed, the prototypical example of why you need explicit deduction guides (that is, why you can't rely entirely on implicit guides) is focused on the constructors of the type. Namely, vector's iterator constructor:
template<typename Iter>
vector(Iter first, Iter last);
A deduction guide is needed to access this constructor because Iter doesn't obviously map to the template parameters of vector<T, A>.
The bottom line is this: explicit deduction guides are built around a class's constructors (though those constructors don't have to exist). They exist to map constructor argument types to class template parameters. If you cannot add a constructor to a class from outside of the class's definition, then it stands to reason that you cannot add an explicit deduction guide from outside of the class's definition either.
Obviously explicit guides are written outside of a template class's definition, but the principle is the same: guides are part of a class's interface.
Implicit conversion via operator Typename does not add a constructor to Typename. It may permit Typename(other_type) to work, but as far as the language standard is concerned, this is a copy/move into Typename. It isn't modifying the definition of Typename.

Related

Why generic lambdas are allowed while nested structs with templated methods aren't?

As far as I understand - generic lambdas are transformed into objects of local scope structs with templated operator(). This makes generic lambda very powerful and easy to use tool. On the other hand one can create structs nested into the function, when however the struct has templated member e.g.:
#include <iostream>
int main() {
struct inner {
template <class T>
void operator()(T &&i) { }
};
return 0;
}
or is templated by itself:
int main() {
template <class T>
struct inner {
void operator()(T &&i) { }
};
return 0;
}
compiler seems to have a problem with compiling it:
error: invalid declaration of member template in local class
and
error: a template declaration cannot appear at block scope
I assume the problem lays more in c++ standard than in compiler bug. What are the reasons lambdas are allowed to have templated members and not the local structures?
I found this qustion, but I think the answer is kind of outdated (I don't think it's true even for c++11).
This is core issue 728, which was filed before generic lambdas were a thing.
You mentioned generic lambdas and that they were identical to local classes with corresponding member template operator(). However, they actually aren't, and the differences are related to implementation characteristics. Consider
template <typename T>
class X {
template <typename>
void foo() {
T t;
}
};
And
template <typename T>
auto bar() {
return [] (auto) {T t;};
};
Instantiating these templates with <void> will be fine in the first case, but ill-formed in the second. Why fine in the first case? foo need not be instantiatable for each particular T, but just one of them (this would be [temp.res]/(8.1)).
Why ill-formed in the second case? The generic lambda's body is instantiated - partially - using the provided template arguments. And the reason for this partial instantiation is the fact that…
…the lexical scopes used while processing a function definition are fundamentally transient, which means that delaying instantiation of some portion of a function template definition is hard to support.
(Richard Smith) We must instantiate enough of the local "template" to make it independent of the local context (which includes template parameters of the enclosing function template).
This is also related to the rationale for
[expr.prim.lambda]/13, which mandates that an entity is implicitly captured by a lambda if it…
names the entity in a potentially-evaluated expression ([basic.def.odr]) where the enclosing full-expression depends on a generic lambda parameter declared within the reaching scope of the lambda-expression.
That is, if I have a lambda like [=] (auto x) {return (typename decltype(x)::type)a;}, where a is some block-scope variable from an enclosing function, regardless of whether x's member typedef is for void or not, the cast will cause a capture of a, because we must decide on this without waiting for an invocation of the lambda. For a discussion of this problem, see the original proposal on generic lambdas.
The bottom line is that completely postponing instantiation of a member template is not compatible with the model used by (at least one) major implementation(s), and since those are the expected semantics, the feature was not introduced.
Was that the original motivation for this constraint? It was introduced sometime between January and May 1994, with no paper covering it, so we can only get a rough idea of the prevailing notions from this paper's justification of why local classes shall not be template arguments:
Class templates and the classes generated from the template are global scope
entities and cannot refer to local scope entities.
Perhaps back then, one wanted to KISS.
I assume the problem lays more in c++ standard
Correct. This is stipulated in [temp] for class templates:
A template-declaration can appear only as a namespace scope or class scope declaration.
and [temp.mem] for member templates:
A local class of non-closure type shall not have member templates.
What are the reasons lambdas are allowed to have templated members and not the local structures?
Because once we had lambdas in C++11, it was deemed that it would be extremely useful to extend that concept to have generic lambdas. There was a proposal for such a language extension, which was revised and revised and adopted.
On the other hand, there has not yet been a proposal presented (as far as I'm aware from a brief search) that lays out the motivation for the need for member templates in local classes that isn't adequately solved by a generic lambda.
If you feel that this is an important problem that needs to be solved, feel free to submit a proposal after laying out a thoughtful motivation for why local member templates are important.

Namespace causes sub-optimal template overload resolution

This is very similar to this question, but I'm not sure the answer there is entirely applicable to the minimal code I've put together that demonstrates the issue. (My code does not use trailing-return types, and there are some other differences as well.) Additionally, the issue of whether MSVC's behavior is legal doesn't seem to be addressed.
In short, I'm seeing the compiler select a generic function template instantiation rather than a more-specific overload when the function template is inside a namespace.
Consider the following set of namespace and class definitions:
namespace DoStuffUtilNamespace
{
template<typename UNKNOWN>
void doStuff(UNKNOWN& foo)
{
static_assert(sizeof(UNKNOWN) == -1, "CANNOT USE DEFAULT INSTANTIATION!");
}
}
class UtilForDoingStuff
{
public:
template <typename UNKNOWN>
void doStuffWithObjectRef(UNKNOWN& ref)
{
DoStuffUtilNamespace::doStuff(ref);
}
};
class MyClassThatCanDoStuff { };
namespace DoStuffUtilNamespace
{
using ::MyClassThatCanDoStuff; // No effect.
void doStuff(MyClassThatCanDoStuff& foo) { /* No assertion! */ }
}
... and the following use-cases:
int main()
{
MyClassThatCanDoStuff foo;
DoStuffUtilNamespace::MyClassThatCanDoStuff scoped_foo;
UtilForDoingStuff util;
DoStuffUtilNamespace::doStuff(foo); // Compiles
DoStuffUtilNamespace::doStuff(scoped_foo); // Compiles
util.doStuffWithObjectRef(foo); // Triggers static assert
util.doStuffWithObjectRef(scoped_foo); // Triggers static assert
}
If the entire DoStuffUtilNamespace is eliminated and all its members are moved to global scope, this compiles fine with G++ and Clang++.
With the namespace, doStuff is of course a dependent name. According to the top-voted answer on the similar question, the standard says:
In resolving dependent names, names from the following sources are considered:
Declarations that are visible at the point of definition of the template.
Declarations from namespaces associated with the types of the function arguments both from the instantiation context and from the definition context.
This seems a little odd to me; I don't understand why the first bullet point would specify that the declarations must be visible at the point of definition of the template rather than at the point of instantiation, since the second bullet point explicitly specifies that some declarations visible only at the point of instantiation are allowed. (If someone would like to offer a rationale, I'd appreciate it, but that's not my question because it's my understanding that questions of the form "why did the standards committee decide X" are off topic.)
So I think that explains why util.doStuffWithObjectRef(foo); triggers the static assertion: doStuff(MyClassThatCanDoStuff&) hasn't been declared at the point of definition of UtilForDoingStuff::doStuffWithObjectRef<UNKNOWN>(UNKNOWN&). And indeed moving the class UtilForDoingStuff definition after the doStuff overload has been defined seems to fix the issue.
But what exactly does the standard mean by "namespaces associated with the types of the function arguments"? Shouldn't the using ::MyClassThatCanDoStuff declaration, together with the explicit scoping of the scoped_foo instance type within the namespace, trigger argument-dependent lookup, and shouldn't this look-up find the non-asserting definition of doStuff()?
Also, the entire code is compiled without error using clang++ -ftemplate-delayed-parsing, which emulates MSVC's template-parsing behavior. This seems preferable, at least in this particular case, because the ability to add new declarations to a namespace at any time is one of the primary appeals of namespaces. But, as noted above, it doesn't quite seem to follow the letter of the law, according to the standard. Is it permissible, or is it an instance of non-conformance?
EDIT:: As pointed out by KIIV, there is a workaround; the code compiles if template specialization is used instead of overloading. I would still like to know the answers to my questions about the standard.
With the namespace, doStuff is of course a dependent name.
You are starting from the wrong premise. There is no ADL for a qualified call like DoStuffUtilNamespace::doStuff(ref). [basic.lookup.argdep]/p1, emphasis mine:
When the postfix-expression in a function call (5.2.2) is an
unqualified-id, other namespaces not considered during the usual
unqualified lookup (3.4.1) may be searched, and in those namespaces,
namespace-scope friend function or function template declarations
(11.3) not otherwise visible may be found.
DoStuffUtilNamespace::doStuff is a qualified-id, not an unqualified-id. ADL doesn't apply.
For this reason, DoStuffUtilNamespace::doStuff is also not a dependent name. [temp.dep]/p1:
In an expression of the form:
postfix-expression ( expression-listopt)
where the postfix-expression is an unqualified-id, the
unqualified-id denotes a dependent name if [...]. 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
(The italicization of dependent name indicate that this paragraph is defining the term.)
Instead, per [temp.nondep]/p1:
Non-dependent names used in a template definition are found using the
usual name lookup and bound at the point they are used.
which doesn't find your later overload declaration.
Specialization works because it's still the same function template declaration that's used; you just supplied a different implementation than the default one.
But what exactly does the standard mean by "namespaces associated with
the types of the function arguments"? Shouldn't the using ::MyClassThatCanDoStuff declaration, together
with the explicit scoping of the scoped_foo instance type within the
namespace, trigger argument-dependent lookup
No. using-declarations do not affect ADL. [basic.lookup.argdep]/p2, emphasis mine:
For each argument type T in the function call, there is a set of
zero or more associated namespaces and a set of zero or more
associated classes to be considered. The sets of namespaces and
classes is determined entirely by the types of the function arguments
(and the namespace of any template template argument).
Typedef names and using-declarations used to specify the types do not contribute to this set. The sets of namespaces and classes are
determined in the following way:
If T is a fundamental type, [...]
If T is a class type (including unions), its associated classes are: the class itself; the class of which it is a member, if any; and its
direct and indirect base classes. Its associated namespaces are the
innermost enclosing namespaces of its associated classes. Furthermore,
if T is a class template specialization, its associated namespaces and
classes also include: the namespaces and classes associated with the
types of the template arguments provided for template type parameters
(excluding template template parameters); the namespaces of which any
template template arguments are members; and the classes of which any
member templates used as template template arguments are members. [
Note: Non-type template arguments do not contribute to the set of associated namespaces. —end note ]
[...]
With template specialization I can get it work:
namespace DoStuffUtilNamespace
{
template<typename UNKNOWN>
void doStuff(UNKNOWN& foo)
{
static_assert(sizeof(UNKNOWN) == -1, "CANNOT USE DEFAULT INSTANTIATION!");
}
}
class UtilForDoingStuff
{
public:
template <typename UNKNOWN>
void doStuffWithObjectRef(UNKNOWN& ref)
{
DoStuffUtilNamespace::doStuff(ref);
}
};
class MyClassThatCanDoStuff { };
namespace DoStuffUtilNamespace
{
using ::MyClassThatCanDoStuff;
template <> void doStuff<MyClassThatCanDoStuff>(MyClassThatCanDoStuff& foo) { /* No assertion! */ }
}
int main()
{
MyClassThatCanDoStuff foo;
DoStuffUtilNamespace::MyClassThatCanDoStuff scoped_foo;
UtilForDoingStuff util;
DoStuffUtilNamespace::doStuff(foo); // Compiles
DoStuffUtilNamespace::doStuff(scoped_foo); // Compiles
util.doStuffWithObjectRef(foo); // Compiles
util.doStuffWithObjectRef(scoped_foo); // Compiles
}
Declarations from namespaces associated with the types of the function arguments both from the instantiation context and from the definition context.
Example with the following code which prints B::foo Demo
namespace A
{
template <typename T>
void foo(const T&) {std::cout << "A::foo" << std::endl;}
template <typename T>
void bar(const T& t) {
foo(t); // thank to ADL, it will also look at B::foo for B::S.
}
}
namespace B
{
struct S {};
void foo(const S&) {std::cout << "B::foo" << std::endl;}
}
int main()
{
B::S s;
A::bar(s);
}
So when calling ?::foo(const B::S&), the second bullet point adds B::foo to the list of overloads.
why template-specialization works in this case
There is only one function:
template<>
void DoStuffUtilNamespace::doStuff<MyClassThatCanDoStuff>(MyClassThatCanDoStuff& foo);
even if it is defined later.
Note that the fact that there is a specialization should be known in the translation unit, else the program is ill formed (doesn't respect ODR).
while overloading doesn't.
You think:
So I think that explains why util.doStuffWithObjectRef(foo); triggers the static assertion: doStuff(MyClassThatCanDoStuff&) hasn't been declared at the point of definition of UtilForDoingStuff::doStuffWithObjectRef<UNKNOWN>(UNKNOWN&). And indeed moving the class UtilForDoingStuff definition after the doStuff overload has been defined seems to fix the issue.
Exactly.

Overloading (not specializing) templates in std namespace

This is very pedantic but in C++03 it was apparently non-conforming for a program to overload (not specialize) a template function in the std namespace: see mention of this here and long discussion on comp.lang.c++.moderated
i.e. this was ok:
namespace std
{
template <>
void swap (Foo & f, Foo & g)
{
// ...
}
}
but this was not (if I understand correctly...):
namespace std
{
template <typename T>
void swap (TempateFoo<T> & f, TempateFoo<T> & g)
{
// ...
}
}
Is this still true in C++11? Also, does this apply to template classes (like std::hash) too, or just template functions?
EDIT: also, is there any example of a standard library implementation such that the latter would break things in practice? And if not, is there a specific reason for disallowing overloads like in the second case above? (what could potentially break in theory?)
It is not possible to define a partial specialization of a function template in C++, so your second example defines an overload not a specialization. Since the standard only allows specializations to be added to namespace std, your overload is illegal.
Is this still true in C++11?
Yes.
Also, does this apply to template classes (like std::hash) too, or just template functions?
You can't overload class templates anyway, you can only overload functions. The same rules apply though, you can only specialize a class template if the specialization depends on a user-defined (meaning non-standard) type.
is there a specific reason for disallowing overloads like in the second case above? (what could potentially break in theory?)
As one example, the implementation might want to take the address of a function but if you've overloaded the function then taking the address could cause an ambiguity and fail to compile, meaning you've just broken valid code in the standard library.
n3376 17.6.4.2.1
The behavior of a C++ program is undefined if it adds declarations or definitions to namespace std or to a
namespace within namespace std unless otherwise specified. A program may add a template specialization
for any standard library template to namespace std only if the declaration depends on a user-defined type
and the specialization meets the standard library requirements for the original template and is not explicitly
prohibited.
17.6.4.2.2
The behavior of a C++ program is undefined if it declares
— an explicit specialization of any member function of a standard library class template, or
— an explicit specialization of any member function template of a standard library class or class template,
or
— an explicit or partial specialization of any member class template of a standard library class or class
template.
A program may explicitly instantiate a template defined in the standard library only if the declaration
depends on the name of a user-defined type and the instantiation meets the standard library requirements
for the original template.

Can a single member of a class template be partially specialized?

I came across an interesting point that I wasn't able to explain or find an explanation for. Consider the following template definition (compiled with mingw g++ 4.6.2):
template <typename T, typename S>
class Foo
{
public:
void f(){}
void g(){}
};
Should we want to, we can fully specialize any single member function:
template <>
void Foo<char,int>::f() {}
But partial specialization fails with an "invalid use of incomplete type 'class Foo<...>'" error:
template <typename T, typename S>
void Foo<T,S*>::f()
{
}
template <typename T>
void Foo<T,int>::f()
{
}
And I can't figure out why. Is it a conscious design decision made to avoid some problem I can't foresee? Is it an oversight?
The notion of partial specialization only exists for class templates (described by §14.5.5) and member templates (i.e. members of a template class that are themselves template functions, described by §14.5.5.3/2). It does not exist for ordinary members of class templates, nor does it exist for function templates – simply because it is not described by the Standard.
Now, you might argue that by giving the definition of a partial specialization of a member function, such as
template <typename T>
void Foo<T,int>::f()
{ }
you implicitly define a partial specialization of the class template: Foo<T,int>. That, however, is explicitly ruled out by the Standard:
(§14.5.5/2) Each class template partial specialization is a distinct template and definitions shall be provided for the members of a template partial specialization (14.5.5.3).
(§14.5.5.3/1) [...] The members of the class template partial specialization are unrelated to the members of the primary template. Class template partial specialization members that are used in a way that requires a definition shall be defined; the definitions of members of the primary template are never used as definitions for members of a class template partial specialization. [...]
The latter implies that it is impossible to implicitly define a partial specialization by simply giving the definition of one of its members: The very existence of that member would not follow from the definition of the primary template, hence defining it is equivalent to defining a member function that wasn't declared, and that isn't allowed (even with non-template classes).
On the other hand, the notion of explicit specialization (or full specialization, as you call it) exists for member functions of class templates. It is explicitly described by the Standard:
(§14.7.3/1) An explicit specialization of any of the following:
[...]
— member function of a class template
[...]
can be declared by a declaration introduced by template<>; [...]
§14.7.3/14 describes the details:
(§14.7.3/14) A member or a member template of a class template may be explicitly specialized for a given implicit instantiation of the class template, even if the member or member template is defined in the class template definition. [...]
Hence, for explicit specializations of members, the instantiation of the rest of the class template works implicitly – it is derived from the primary template definition, or any partial specializations if defined.
I tried to find a succinct quote from the standard, but I don't think there is one. The fact is, there is no such thing as a partial specialization of a template function (or, for that matter, of a template alias). Only class templates can have partial specializations.
Let's forget about templates for a second. In C++, there is a big difference between class names and function names. There can only be one definition of a class within a given scope. (You can have various declarations, but they all refer to the One True Class.) So the name really identifies the class.
A function name, on the other hand, is a kind of group identity. You can define any number of functions within a scope with exactly the same name. When you use a function name to call a function, the compiler has to figure out which function you really meant by looking at the various possibilities and matching the signature of each of them with the supplied arguments. There's no relationship between the various functions which share a name; they're completely separate entities.
So, no big deal. You knew all this, right? But now let's go back to templates.
The name of a templated class is still unique. Although you can define partial specializations, you have to explicitly specialize the same templated class. This mechanism looks superficially like the function-name resolution algorithm referred to above, but there are significant differences -- one of them is that, unlike function prototypes, you cannot have two class templates in the same scope with different kinds of template parameters.
Templated functions, on the other hand, have no need to define unique names. Templating does not replace the normal function overload mechanism. So when the compiler is trying to figure out what a function name means, it has to consider all templated and non-templated declarations for that function name, resolve the templated ones to a set of template parameter assignments (if possible) and then once it has a list of possible function objects, select the best one with normal overload resolution.
That's quite a different algorithm from the templated class template parameter resolution. Instead of just matching a list of provided template arguments with a list of declared template parameters, which is how it resolves class templates, it has to take each templated function which might possibly match (has at least the right number of parameters, for example); deduce template parameters by unifying the supplied arguments with the template; and then add the resolve specialization to the overload set for a further round of overload resolution.
I suppose it would have been possible to have added partial specialization resolution into that process as well, but the interactions between partial specialization and function overloading strike me as likely to lead to pseudo-magical behaviour. In the event, it wasn't necessary and so there is no such mechanism. (You can fully specialize a function template. Full specialization means that there are no template arguments to deduce, so it's not a problem.)
So that's the scoop: you can't partially specialize a templated function, but there is nothing stopping you from providing any number of function templates with the same name. All of them will be considered in overload resolution, and the best one will win, as usual.
Usually, that's actually sufficient for your overloading needs. You should think about templated functions just the same way you think about normal functions: come up with a way to select the one you want based on the supplied arguments. If you feel you really need to supply template parameters in a function call, rather than having them be deduced, just make the function a (possibly static) member of a templated class, and supply the template arguments to the class.
Hope that helps...
I think that the difference is that when you do the first (valid) explicit specialization of f:
template <>
void Foo<char,int>::f() {}
You are doing an implicit instantiation of Foo<char,int>. But when you try the partial specialization with:
template <typename T>
void Foo<T,int>::f()
{
}
The compiler would need to instantiate implicitly Foo<T,int> before doing the specialization, but it cannot do that because of the T. And it fails.
You can check that is the case with the following code:
template <typename T, typename S>
class Foo
{
public:
void f(){}
void g(){}
};
template <>
void Foo<char,int>::f() //line 11
{}
template <>
class Foo<char,int> //line 15
{};
With g++ it gives the errors:
test.cpp:15:7: error: specialization of ‘Foo<char, int>’ after instantiation
test.cpp:15:7: error: redefinition of ‘class Foo<char, int>’
test.cpp:2:7: error: previous definition of ‘class Foo<char, int>’
With clang++ is a bit clearer:
test.cpp:15:7: error: explicit specialization of 'Foo<char, int>' after instantiation
class Foo<char,int>
^~~~~~~~~~~~~
test.cpp:11:6: note: implicit instantiation first required here
void Foo<char,int>::f()
^

ADL and friend injection

Consider this code:
template <int N>
struct X
{
friend void f(X *) {}
};
int main()
{
f((X<0> *)0); // Error?
}
compilers seem to heavily disagree. (MSVC08/10 says no, GCC<4.5 says yes, but 4.5 says no, sun 5.1 says yes, intel 11.1 says yes too but comeau says no (both are EDG)).
According to "C++ Templates - The complete guide":
... it is assumed that a call
involving a lookup for friends in
associated classes actually causes the
class to be instantiated ... Although
this was clearly intended by those who
wrote the C++ standard, it is not
clearly spelled out in the standard.
I couldn't find the relevant section in the standard. Any reference?
Consider this variation:
template <int N>
struct X
{
template <int M>
friend void f(X<M> *) {}
};
template <>
struct X<0>
{
};
int main()
{
X<1>();
f((X<0> *)0); // Error?
}
The key issue here is wether the viable function injected by X<1> should be visible during ADL for X<0>? Are they associated? All compilers mentioned above accept this code, except for Comeau which only accepts it in relaxed mode. Not sure what the standard has to say about this either.
What's your take on that?
The Standard says at 14.7.1/4
A class template specialization is implicitly instantiated if the class type is used in a context that requires a completely-defined object type or if the completeness of the class type affects the semantics of the program; in particular, if an expression whose type is a class template specialization is involved in overload resolution, pointer conversion, pointer to member conversion, the class template specialization is implicitly instantiated (3.2);
Note that Vandervoorde made an issue report here, and the committee found
The standard already specifies that this creates a point of instantiation.
For your second case - you need to consider the associated classes and namespaces of the argument f(X<0>*). These are, since this is a pointer to a class template specialization (note that "template-id" below is not quite correct - C++0x corrected that to use the correct term) and also a pointer to a class (this confusing split was also corrected in C++0x - it lists these two cases in one bullet point).
If T is a template-id, its associated namespaces and classes are the namespace in which the template is
defined; [... lots of noise ...]
If T is a class type (including unions), its associated classes are: the class itself; the class of which it is a member, if any; and its direct and indirect base classes. Its associated namespaces are the namespaces in which its associated classes are defined.
So to summary, we have as associated classes are X<0> and the associated namespaces are the global namespace. Now the friend functions that are visible are
Any namespace-scope friend functions declared in associated classes are visible within their respective namespaces even if they are not visible during an ordinary lookup
There is no friend function declared in X<0> so the friend function declaration is not visible when looking into the global namespace. Note that X<0> is an entirely different class-type than X<1>. The implicit instantiation of X<1> you do there has no effect on this call - it just adds a non-visible name into the global namespace that refers to a friend function of class X<1>.