I have never gotten a great explanation of how template argument deduction really works, so I'm not sure how to explain behavior I'm seeing in the following:
template<typename T>
struct Base
{
protected:
template<bool aBool = true>
static void Bar(int)
{
}
};
template<typename T>
class Derived : public Base<T>
{
public:
void Foo() { Base<T>::Bar<false>(5); }
};
int main()
{
Derived<int> v;
v.Foo();
return 0;
}
This code won't build, and gives the error:
main.cpp: In instantiation of 'void Derived<T>::Foo() [with T = int]':
main.cpp:25:8: required from here main.cpp:19:15: error: invalid
operands of types '<unresolved overloaded function type>' and 'bool'
to binary 'operator<'
If you change the 2 Base<T>s in Derived to Base<int>, it compiles. If you change the call to Bar() to Base<T>::template Bar<false>(5);, it also compiles.
The one-liner I saw as an explanation for this is that the compiler doesn't know that Bar is a template, presumably because it doesn't know what Base is until a specialization of Derived is declared. But once the compiler starts generating code for Foo(), Base<T> has already been defined, and the type of Bar can be determined. What is causing the compiler to assume the symbol Bar is not a template, and attempting to apply operator<() instead?
I assume it has to do with the rules of when templates are evaluated in the compilation process - I guess what I'm looking for is a good comprehensive explanation of this process, such that the next time I run into code like the below, I can deduce the answer without the help of the good people on stack overflow.
Note I'm compiling with g++ 4.7, with c++x11 support.
void Foo() { Base<T>::Bar<false>(5); }
In this context Base<T> is a dependent name. To access a member template of a dependent name you need to add the template keyword:
void Foo() { Base<T>::template Bar<false>(5); }
Otherwise Base<T>::Bar will be parsed as a non-template member and < as less-than.
As of why the template is required, the reason is two-phase lookup. The error is triggered during the first pass, before the type is substituted, so the compiler does not know what is the definition of Base<T>. Consider for example that you added an specialization of Bar for int that had a non-template Bar member (say for example an int member). Before substituting T into Foo, the compiler does not know if there is an specialization for the type.
Related
In following code, could anyone explain why do I get following error:
"error: no type named ‘type’ in struct std::enable_if<false, double>
According to my understanding of enable_if_t, there should not be any problem at compile time if I am not using function p. It should simply not get generated for simple types.
But when I change condition to !is_class_v<T>, it works fine for simple types but then it stops working for class types.
template<typename T>
class Smart_class
{
public:
enable_if_t<is_class_v<T>, T> p(T t)
{
};
};
void f()
{
Smart_class<double> a;
}
Quoting from temp.inst/3.1:
The implicit instantiation of a class template specialization causes the implicit instantiation of the declarations, but not of the definitions, of the non-deleted class member functions...
This is your case, the declaration of p member function is instantiated and it refers to the non-existing return type.
Firstly, some standard's quoted passage
If a template specialization X is referenced in a context that depends on a template-parameter of some surrounding template Y, the given point of instantation depends on the point of instantation of Y.
If X is a function template specialization, the point of instantiation is that of Y.
If X is a class template specialization, the point of instantiation is immediately before the point of instantiation of Y.
Otherwise, the given point of instantiation is tied to the location of the namespace scope declaration/definition (D) which contains the statement referring to X.
If X is a function template specialization, the point of instantiation is immediately after D.
If X is a class template specialization, the point of instantiation is immediately before D.
Some code here
#include <iostream>
template<int N>
struct state {
friend auto call(state<N>);
};
template<int N>
struct add_state {
friend auto call(state<N>) {
return N;
}
};
template<typename T, int N>
T show() {
add_state<N> d;
return T{};
}
template<typename T,int N>
class data {
public:
T c = show<T,N>();
};
#1,#3,#2
int main() {
data<int, 0> t;
call(state<0>{});
}
So, according to the above rules, when instantiating class data<int, 0>, then the point of instantiation is at #1.
Then show<T,N> depends on template class data's template parameters. So the point of instantiation for show<int,0> is at #2.
Then add_state<N> depends on template function show's template parameters. So according to the rules, the point of instantiation for add_state<0> is at #3.
At #3 auto call(state<0>) has been defined, call(state<0>{}) should be linked but in the fact, the compiler reports errors as follows:
clang:
main.cpp:24:2: error: function 'call' with deduced return type cannot be used before it is defined
call(state<0>{});
^
main.cpp:4:14: note: 'call' declared here
friend auto call(state<N>);
^
1 error generated.
g++:
main.cpp: In function ‘int main()’:
main.cpp:24:17: error: use of ‘auto call(state<0>)’ before deduction of ‘auto’
call(state<0>{});
^
Why? Does my understand about the point of instantiation has some mistakes?
If not, why does the compiler report these errors?
According to [temp.inst]/2.1, when a class template is implicitly instantiated, only the declaration of friends are instantiated:
The implicit instantiation of a class template specialization causes the implicit instantiation of the declarations, but not of the definitions, default arguments, or noexcept-specifiers of the class member functions, member classes, scoped member enumerations, static data members, member templates, and friends;
So at #3 auto call(state<N>) is only declared. Moreover, this declaration is not found by ordinary unqualified name look-up.
Nevertheless I do not think that it makes your code formaly ill-formed. Your code is so strange that it is possible that such a situation has never been thought about by standard commitee members or compiler implementers: usualy inline friend functions are defined in the class that makes the friend function visible through ADL (Argument Dependent Name Lookup). This is certainly also what excepects a compiler.
So at call(state<0>{}) inside main, the declaration of call is found by ADL inside the definition of state and the compiler just don't think about looking for a potential definition of this function in the somehow unrelated class add_state. So it fails to deduce auto.
I'm not too confident myself in this matter, but in hope that this might prove useful I put together another working example, other than the ones already suggested:
#include <iostream>
// forward declaration of the
// add_state template
template<int>
struct add_state;
template<int N>
struct state {
// Note: we generate the state here
// so that the compiler will see the
// definition of the call function
add_state<N> t;
friend auto call(state<N>);
};
template<int N>
struct add_state {
friend auto call(state<N>) {
return N;
}
};
int main() {
auto val = call(state<42>{});
std::cout << val << std::endl;
return 0;
}
I'm not sure if this will help. But I hope so, as I, too would be interested in a good explanation.
Your issue is here:
template<int N>
struct state {
friend auto call(state<N>);//<--no way of telling return type !
};
The compiler has absolutely no way of telling of what the call functions returns and has to give up.
The fix is obvious as well, just give it something to work with, eg.:
friend auto call(state<N>) {return N;}
If used int instead of auto got error:
main.cpp:15: undefined reference to `call(state<0>)'
collect2.exe: error: ld returned 1 exit status
When added {return N;} to friend int call(state<N>), worked fine.
Then replaced back int to auto, it also works.
The following is invalid code:
struct foo {
struct bar;
bar x; // error: field x has incomplete type
struct bar{ int value{42}; };
};
int main() { return foo{}.x.value; }
This is quite clear, as foo::bar is considered incomplete at the point where foo::x is defined.
However, there seems to be a "workaround" which makes the same class definition valid:
template <typename = void>
struct foo_impl {
struct bar;
bar x; // no problems here
struct bar{ int value{42}; };
};
using foo = foo_impl<>;
int main() { return foo{}.x.value; }
This works with all major compilers.
I have three questions about this:
Is this indeed valid C++ code, or just a quirk of the compilers?
If it is valid code, is there a paragraph in the C++ standard that deals with this exception?
If it is valid code, why is the first version (without template) considered invalid? If the compiler can figure out the second option, I don't see a reason why it wouldn't be able to figure out the first one.
If I add an explicit specialization for void:
template <typename = void>
struct foo_impl {};
template<>
struct foo_impl<void> {
struct bar;
bar x; // error: field has incomplete type
struct bar{ int value{42}; };
};
using foo = foo_impl<>;
int main() { return foo{}.x.value; }
It once again fails to compile.
The real answer might be ¯\_(ツ)_/¯, but it's probably currently okay because templates are magical, but it may be more explicitly not okay pending some other core issue resolutions.
First, the main problem of course is [class.mem]/14:
Non-static data members shall not have incomplete types.
This is why your non-template example is ill-formed. However, according to [temp.point]/4:
For a class template specialization, a class member template specialization, or a specialization for a class member of a class template, if the specialization is implicitly instantiated because it is referenced from within another template specialization, if the context from which the specialization is referenced depends on a template parameter, and if the specialization is not instantiated previous to the instantiation of the enclosing template, the point of instantiation is immediately before the point of instantiation of the enclosing template. Otherwise, the point of instantiation for such a specialization immediately precedes the namespace scope declaration or definition that refers to the specialization.
Which suggests that foo_impl<void>::bar is instantiated before foo_impl<void>, and hence it's complete at the point where the non-static data member of type bar is instantiated. So maybe it's okay.
However, core language issues 1626 and 2335 deal with not-exactly-the-same-but-still-quite-similar issues regarding completeness and templates, and both point to desiring to make the template case more consistent with the non-template case.
What does all of this mean when viewed as a whole? I'm not sure.
I think this example is explicitly allowed by
17.6.1.2 Member classes of class templates [temp.mem.class]
1
A member class of a class template may be defined outside the class template definition in which it is declared.
[Note: The member class must be defined before its first use that requires an instantiation (17.8.1) For example,
template<class T> struct A {
class B;
};
A<int>::B* b1; // OK: requires A to be defined but not A::B
template<class T> class A<T>::B { };
A<int>::B b2; // OK: requires A::B to be defined
—end note ]
This should work fine too:
template <typename = void>
struct foo_impl {
struct bar;
bar x; // no problems here
};
template<typename T>
struct foo_impl<T>::bar{ int value{42}; };
using foo = foo_impl<>;
int main()
{
return foo{}.x.value;
}
More details about the accepted answer
I am not sure that the accepted answer is the correct explanation, but it is the most plausible one for now. Extrapolating from that answer, here are the aswers to my original questions:
Is this indeed valid C++ code, or just a quirk of the compilers? [ It is valid code. ]
If it is valid code, is there a paragraph in the C++ standard that deals with this exception? [ [temp.point]/4 ]
If it is valid code, why is the first version (without template) considered invalid? If the compiler can figure out the second option, I don't see a reason why it wouldn't be able to figure out the first one. [ Because C++ is weird - it handles class templates differently than classes (you could have probably guessed this one). ]
Some more explanations
What seems to be happening
When instantiating foo{} in main the compiler instantiates an (implicit) specialization for foo_impl<void>. This specialization references foo_impl<void>::bar on line 4 (bar x;). The context is within a template definition so it depends on a template parameter, and the specialization foo_impl<void>::bar is obviously not previously instantiated, so all the preconditions for [temp.point]/4 are fulfilled, and the compiler generates the following intermediate (pseudo)code:
template <typename = void>
struct foo_impl {
struct bar;
bar x; // no problems here
struct bar{ int value{42}; };
};
using foo = foo_impl<>;
// implicit specialization of foo_impl<void>::bar, [temp.point]/4
$ struct foo_impl<void>::bar {
$ int value{42};
$ };
// implicit specialization of foo_impl<void>
$ struct foo_impl<void> {
$ struct bar;
$ bar x; // bar is not incomplete here
$ };
int main() { return foo{}.x.value; }
About specialization
As per [temp.spec]/4:
A specialization is a class, function, or class member that is either instantiated or explicitly specialized.
so the call to foo{}.x.value in the original implementation with templates qualifies as a specialization (this was something new to me).
About the version with explicit specialization
The version with explicit specialization does not compile as it seems that:
if the context from which the specialization is referenced depends on a template parameter
no longer holds, so the rule from [temp.point]/4 does not apply.
I'll answer the third part of your question - as IANALL (not a language lawyer).
The code is invalid for the same reason it's invalid to use a function before it has been declared - even though the compiler can figure out what the function's supposed to be by going further down in the same translation unit. And the cases are similar also in the sense that if you happen to have just a declaration with no definition, that's good enough for the compiler, while here you happen to have a template definition before the instantiation.
So the point is: The language standard mandates that the compiler does not look ahead for you when you want to define something (and a class template is not a definition of a class).
The following bit of code fails to compile on gcc 4.5.3
struct Frobnigator
{
template<typename T>
void foo();
template<typename T>
void bar();
};
template<typename T>
void Frobnigator::bar()
{
}
template<typename T>
void Frobnigator::foo()
{
bar<T>();
}
template<> // error
void Frobnigator::foo<bool>()
{
bar<bool>();
}
template<>
void Frobnigator::bar<bool>()
{
}
int main()
{
}
Error message: specialization of ‘void Frobnigator::bar() [with T = bool]’ after instantiation. I finally resolved this problem by having the specialization of Frobnigator::bar<bool>() appear before Frobnigator::foo<bool>(). Clearly the order in which the methods appear matter.
Why then is the following lite version of the above code, in which the the specialization of bar appears after the generic version, valid ?
struct Frobnigator
{
template<typename T>
void foo();
};
template<typename T>
void Frobnigator::bar()
{
}
template<>
void Frobnigator::bar<bool>()
{
}
int main()
{
}
Your first code is not correct by standard.
n3376 14.7.3/6
If a template, a member template or a member of a class template is explicitly specialized then that specialization shall be declared before the first use of that specialization that would cause an implicit instantiation
to take place, in every translation unit in which such a use occurs; no diagnostic is required.
In your case - implicit instantiation of bar function with type bool is required by its usage in foo<bool>, before explicit specialization declaration.
Clearly the order in which the methods appear matter.
Indeed; as is usually the case in C++, you can't use something before it's declared, and this applies to explicit template specialisations as well as most other things.
Using bar<bool> (by calling it from foo<bool>) without a previous declaration of an explicit specialisation causes that specialisation to be instantiated from the generic template, if it hasn't already been. You'll need at least a declaration of the explicit specialisation to prevent that.
Why is this the case, considering that the specialization of bar appears after the generic version in the following lite version of the above code
The second example differs by not instantiating foo<bool> at all. The issue isn't that the specialisation is declared after the generic template (which must be the case), but that it's declared after that specialisation has already been instantiated.
If I thought I knew anything about C++ then it was that you can't overload functions by return type.
So can anyone explain what is going on here please?
class A { public: typedef int _foo; };
class B {};
template<class T>
typename T::_foo Foo(int)
{
cout << "Foo(int)\n"; return typename T::_foo();
}
template<class T>
typename T Foo(char)
{
cout << "Foo(char)\n"; return typename T();
}
int main()
{
Foo<A>(0); // Writes "Foo(int)", as expected.
Foo<B>(0); // Writes "Foo(char), expected error unable to compile template.
return 0;
}
There are two classes A and B. A defines typedef _foo, B does not. There are two overloads of function template Foo, Foo(int) and Foo(char). Foo(int) returns T::_foo, Foo(char) returns T.
Foo(0) is then called twice. This is an exact match for Foo(int) so I would expect Foo<A>(0) to compile ok, and Foo<B>(0) to fail to compile since B does not define the type _foo used in the template.
What actually happens is that Foo<B>(0) completely ignores Foo(int) and instantiates Foo(char) instead. But by the normal rules of overload resolution Foo(0) is clearly an exact match for Foo(int), and the only thing that makes Foo(char) a more viable match is the return type which should not be considered.
To verify that it is the return value that is affecting the overload resolution just add this:
template<class T>
void Bar(int) { typename T::_foo a; cout << "Bar(int)\n"; }
template<class T>
void Bar(char) { cout << "Bar(char)\n"; }
Bar<A>(0); // Writes "Bar(int), as expected.
//Bar<B>(0); // Error C2039: '_foo' : is not a member of 'B', as expected.
This makes it clear that in the absence of the return value Foo(int) is indeed the correct overload, and that if the template cannot resolve the types used from its template argument that failure to compile is the normal outcome.
You're not overloading on return type, you're specializing a function template and when the Foo<B>(int) specialization forms the invalid type B::_foo that specialization is removed from the overload set by SFINAE, leaving the Foo<B>(char) function as the only viable function.
In more detail, the call to Foo<A>(0) first performs name lookup to find all the Foo names in scope, then instantiates any function templates to find the overload candidates, then overload resolution chooses the best match.
The step of instantiating the function templates produces these two function declarations:
int Foo<A>(int);
A Foo<A>(char);
Overload resolution chooses the first one as the best match.
However when calling Foo<B>(0) the instantiations produce these declarations:
<invalid type> Foo<B>(int);
B Foo<B>(char);
The first declaration is not valid, so there is only one candidate for overload resolution, so that is the one that gets called.
In your Bar example the invalid type that gets formed during instantiation is not in "the immediate context" of the function declaration (it's in the function definition i.e. body) so SFINAE does not apply.
template<class T>
typename T::_foo Foo(int);
template<class T>
typename T Foo(char);
So your code declares this overloaded function. That's nice.
Foo<A>(0);
In this case, the compiler tries to fill out the template for the prototypes declared above, which would be:
int Foo(int);
A foo(char);
And since you're passing an integer as a parameter, the first is a better match, so the compiler uses that one.
Foo<B>(0);
Again the compiler sees this line and tries to fill out the template for the prototypes, but...
WTFDOESNTMAKESENSE?!?!? Foo(int);
A foo(char);
So clearly, the first one doesn't even make sense, so it discards that and uses the second overload. This actually has nothing to do with return types, it has to do with how template prototypes are filled out before it decides which function you mean. Here's your example rearranged to clarify:
template<class T>
int foo(T::_foo) {}
template<class T>
int foo(char) {}
int main() {
foo<A>(0); //uses the first, `int foo(int)` better than `int foo(char)`
foo<B>(0); //uses the second, because the first doesn't work with B.
This is called SFINAE, and note that it only works in very particular circumstances in template parameters, return types, and function parameters, but not the function body itself. This is why your "verification" caused an error, because it can't tell that one of the functions is invalid from the prototype, and the prototype is the only thing considered when it's deciding between overloads.