Following program looks pretty OK to me. But I can not get it compiled.
#include <iostream>
#include <vector>
using namespace std;
int main()
{
struct a
{
int i;
int j;
};
std::vector<a*> vecA;
a* pA = new a;
pA->i = 4;
pA->j = 9;
vecA.push_back(pA);
return 0;
}
It generates following error.
struct_update.cc: In function ‘int main()’:
struct_update.cc:32:19: error: template argument for ‘template<class _Alloc> class std::allocator’ uses local type ‘main()::a*’
struct_update.cc:32:19: error: trying to instantiate ‘template<class _Alloc> class std::allocator’
struct_update.cc:32:19: error: template argument 2 is invalid
struct_update.cc:32:25: error: invalid type in declaration before ‘;’ token
struct_update.cc:39:10: error: request for member ‘push_back’ in ‘vecA’, which is of non-class type ‘int’
This isn't true anymore in the new C++11 standard, but current compilers don't fully implement it yet.
A local type can't be a template parameter. Move your structure definition above main, and everything will work.
Or update your compiler to one that supports this part of C++11.
Here's the restriction from C++03 section 14.3.1 ([temp.arg.type]), which is removed in C++11:
A local type, a type with no linkage, an unnamed type or a type compounded from any of these types shall not be used as a template-argument for a template type-parameter.
Move the structure definition out of main function.
struct a
{
int i;
int j;
};
int main()
{
std::vector<a*> vecA;
a* pA = new a;
pA->i = 4;
pA->j = 9;
vecA.push_back(pA);
In C++03 you cannot do this
A local type, a type with no linkage, an unnamed type or a type compounded from any of these types shall not be used as a template-argument for a template type-parameter.
In C++11 i think you can according to the standard. Even though my Visual Studio 11 compiler refuses to allow it
Related
Why isn't it possible to pass std::cout's address as template argument?
Or if it is possible then how?
Here is what I tried:
#include <iostream>
template<std::ostream* stream>
class MyClass
{
public:
void disp(void)
{ (*stream) << "hello"; }
};
int main(void)
{
MyClass<&(std::cout)> MyObj;
MyObj.disp();
return 0;
}
And the error message I got from clang++ -std=c++11 :
main.cpp:15:11: error: non-type template argument does not refer to any declaration
MyClass<&(std::cout)> MyObj;
^~~~~~~~~~~
main.cpp:6:24: note: template parameter is declared here
template<std::ostream* stream>
^
1 error generated.
and from g++ -std=c++11 :
main.cpp: In function ‘int main()’:
main.cpp:15:22: error: template argument 1 is invalid
MyClass<&(std::cout)> MyObj;
^
main.cpp:15:29: error: invalid type in declaration before ‘;’ token
MyClass<&(std::cout)> MyObj;
^
main.cpp:16:8: error: request for member ‘disp’ in ‘MyObj’, which is of non-class type ‘int’
MyObj.disp();
^
Any ideas?
Before C++17 removed this restriction, the syntactic form of a template argument for a pointer or reference template parameter was restricted. N4140 [temp.arg.nontype]/1.3 says that it must be
expressed (ignoring parentheses) as & id-expression, where
the id-expression is the name of an object or function, except that
the & may be omitted if the name refers to a function or array and
shall be omitted if the corresponding template-parameter is a
reference
(std::cout) isn't an id-expression. It's a primary-expression.
The "(ignoring parentheses)" part was added by Core issue 773, and is apparently meant to permit (&i), not &(i).
This fixes your code, omit the parenthesis:
#include <iostream>
template<std::ostream* stream>
class MyClass
{
public:
void disp(void) {
(*stream) << "hello";
}
};
int main(void)
{
MyClass<&std::cout> MyObj;
MyObj.disp();
return 0;
}
Live Demo
A more detailed explanation why can be found here:
Error with address of parenthesized member function
This seems to be another "who's doing it well?" question since gcc 6.0.0 and clang 3.7.0 behaves different.
Let's suppose we have a variable template which takes a const char * as non template argument and is specialized for a given pointer:
constexpr char INSTANCE_NAME[]{"FOO"};
struct Struct{ void function() const { std::cout << __PRETTY_FUNCTION__; } };
std::ostream &operator <<(std::ostream &o, const Struct &) { return o << INSTANCE_NAME; }
template <const char *> char Value[]{"UNKNOWN"};
// spezialization when the pointer is INSTANCE_NAME
template < > Struct Value<INSTANCE_NAME>{};
Note that the template variable have different types depending on the specialization. Ten we have two template functions, each of one takes a const char * as non template argument and forwards it to the variable template:
template <const char *NAME> void print()
{
std::cout << Value<NAME> << '\n';
}
template <const char *NAME> void call_function()
{
Value<NAME>.function();
}
Then, calling this functions results in different behaviours:
int main()
{
print<INSTANCE_NAME>();
call_function<INSTANCE_NAME>();
return 0;
}
Code Here
clang 3.7.0 prints FOO and void Struct::function() const (as I was expecting) while gcc 6.0.0 fails to compile with the error below:
request for member 'function' in 'Value', which is of non-class type 'char [8]'
I'm almost sure that gcc failed to forward the template non-type argument NAME to the variable template Value in the function call_function and for this reason it selects the unspecialized variable template which is the one with 'char [8]' type...
It is acting like it is copying the template argument. This only happens when calling a member function of the object, if we comment the body of call_function, the output is FOO not UNKNOWN, so in the print function the forwarding is working even in gcc.
So
What's the correct behaviour? (mi bet is for clang)
How can I open a bug ticket for the compiler who's doing it wrong?
The interesting thing is that GCC is even self-contradictory in this example.
Lets declare an incomplete template class which should give is some nice compiler messages that we can abuse:
template <typename T>
struct type_check;
We'll also make another const char* that we can use for testing:
constexpr char NOT_FOO[]{"NOT_FOO"};
Now we'll see what the compiler chokes on:
template <const char *NAME> void foo()
{
type_check<decltype(Value<FOO>)> a;
type_check<decltype(Value<NAME>)> b;
type_check<decltype(Value<NOT_FOO>)> c;
type_check<decltype(Value<FOO>.foo())> d;
type_check<decltype(Value<NAME>.foo())> e;
type_check<decltype(Value<NOT_FOO>.foo())> f;
}
Here are the errors which GCC 5.1.0 produces (edited a bit for clarity):
test.cpp:21:38: error: ‘type_check<Foo> a’ has incomplete type
type_check<decltype(Value<FOO>)> a;
^
test.cpp:22:39: error: ‘type_check<Foo> b’ has incomplete type
type_check<decltype(Value<NAME>)> b;
test.cpp:25:42: error: ‘type_check<char [8]> c’ has incomplete type
type_check<decltype(Value<NOT_FOO>)> c;
^
test.cpp:23:44: error: ‘type_check<void> c’ has incomplete type
type_check<decltype(Value<FOO>.foo())> c;
test.cpp:24:37: error: request for member ‘foo’ in ‘Value<NAME>’, which is of non-class type ‘char [8]’
type_check<decltype(Value<NAME>.foo())> d;
test.cpp:28:40: error: request for member ‘foo’ in ‘Value<((const char*)(& NOT_FOO))>’, which is of non-class type ‘char [8]’
type_check<decltype(Value<NOT_FOO>.foo())> f;
Let's take these one at a time.
Error 1:
test.cpp:21:38: error: ‘type_check<Foo> a’ has incomplete type
type_check<decltype(Value<FOO>)> a;
In the first error, we can see that GCC correctly deduces that the type of Value<FOO> is Foo. This is what we expect.
Error 2:
test.cpp:22:39: error: ‘type_check<Foo> b’ has incomplete type
type_check<decltype(Value<NAME>)> b;
Here, GCC correctly does the forwarding and works out that Value<NAME> is of type Foo.
Error 3:
test.cpp:25:42: error: ‘type_check<char [8]> c’ has incomplete type
type_check<decltype(Value<NOT_FOO>)> c;
Great, Value<NOT_FOO> is "UNKNOWN", so this is correct.
Error 4:
test.cpp:23:44: error: ‘type_check<void> c’ has incomplete type
type_check<decltype(Value<FOO>.foo())> c;
This is fine, Value<FOO> is Foo, which we can call foo on, returning void.
Error 5:
test.cpp:24:37: error: request for member ‘foo’ in ‘Value<NAME>’, which is of non-class type ‘char [8]’
type_check<decltype(Value<NAME>.foo())> d;
This is the odd one. Even though in error 2 we can see that GCC knows that the type of Value<NAME> is Foo, when it tries to do the lookup for the foo function, it gets it wrong and uses the primary template instead. This could be some bug in the function lookup which doesn't correctly resolve the values of non-type template arguments.
Error 6:
test.cpp:28:40: error: request for member ‘foo’ in ‘Value<((const char*)(& NOT_FOO))>’, which is of non-class type ‘char [8]’
type_check<decltype(Value<NOT_FOO>.foo())> f;
Here we can see the compiler correctly choose the primary template when working out what Value<NOT_FOO> is. The thing that interests me is the (const char*)(& NOT_FOO)) which GCC deduces as the type of NOT_FOO. Maybe this is a pointer to the issue? I'm not sure.
I would suggest filing a bug and pointing out the discrepancy. Maybe this doesn't fully answer your question, but I hope it helps.
There is a reasonable consensus that variable template specializations are permitted to alter the type of the variable template: C++1y/C++14: Variable Template Specialization?
The behavior of gcc is particularly interesting if the default type of Value is changed to a type with a function method:
struct Unknown{ void function() const { std::cout << __PRETTY_FUNCTION__; } };
template <const char *> Unknown Value;
prog.cc: In instantiation of 'void call_function() [with const char* NAME = ((const char*)(& INSTANCE_NAME))]':
prog.cc:26:18: required from here
prog.cc:20:5: error: 'Unknown::function() const' is not a member of 'Struct'
Value<NAME>.function();
^
The bug appears to be that where the non-specialized variable template has a type that is not dependent on the variable template template parameters, gcc assumes within template methods that use that variable template that the variable template always has that type.
The workaround, as usual, is to unconditionally forward the variable template to a class template with specialization(s) of the class template, and with the necessary fiddling for ODR compliance.
Another (possibly easier) workaround is to make the non-specialized variable template type somehow dependent on the variable template template parameters; in your case this would work:
template <const char *P> decltype(*P) Value[]{"UNKNOWN"};
I can't find a corresponding issue in gcc bugzilla so you might want to enter a new one. Here's a minimal example:
struct U { void f() {} };
struct V { void f() {} };
template<class T> U t;
template<> V t<int>;
template<class T> void g() { t<T>.f(); }
int main() { g<int>(); }
I have the following code:
template <const char *p>
struct A{};
template <int i>
struct E{};
extern constexpr int i = 0;
constexpr float f = 0.f;
extern constexpr char c = 0;
int main(int argc, const char *argv[])
{
A<&c> b; //works
A<(const char *)(&i)> a; //Error: could not convert template argument ‘(const char*)(& i)’ to ‘const char*’
E<(int)f> e; //works
return 0;
}
why the line A<(const char *)(&i)> a; is wrong? I compiled it with g++-4.6.1 with -std=c++0x.
EDIT: As Charles suggested that reinterpret_cast is not permitted in a constant expression, I change the above code to the following:
struct Base{};
struct Derived : public Base {};
template <const Base *p>
struct A{};
extern constexpr Base base = {};
extern constexpr Derived derived = {};
A<&base> a; //works
A<(const Base*)&derived> b; //error: could not convert template argument ‘(const Base*)(& derived)’ to ‘const Base*’
Therefore, not only reinterpret_cast is not allowed. Using A<static_cast<const base*>(&derived) yields the same error.
To #BЈовић:
A<(const Base*)(0)> b; // error: could not convert template argument ‘0u’ to ‘const Base*’
As for "the standard says so" answers, look in the comments.
The real question is Why would this not be allowed?
It makes a lot of sense to categorically refuse type conversions in template arguments, because what you are really interested in is the value of the template argument. Type conversions however can become arbitrarily complicated and are not forced to be constexprs. The standard (apparently) simply doesn't make an exception for built-in (primitive) types.
Note that your E<(int)f> example is also refuted by clang with the reason:
error: non-type template argument of type 'int' is not an integral constant expression
Why gcc allows this is dubious, but I'd assume it allows you to use constexprs that you could explicitly declare. Note that this is not possible to sneak the address of i in the parameter list of A.
template<class T> struct A {
typedef int Int;
A::Int b; // Line 1 (fails)
Int c; // Line 2 (compiles)
};
int main(){
A<int> x;
x.c = 13;
}
Errors
error: ISO C++ forbids declaration of ‘Int’ with no type
error: extra qualification ‘A<T>::’ on member ‘Int’
error: expected ‘;’ before ‘b’
Line 1 fails but Line 2 compiles. Why?
You need a typename
typename A::Int b;
The typename keyword is required because the member is referred to using a qualified name A::Int.
Int c is fine because no qualified name is used in that case.
14.6/6
Within the definition of a class template or within the definition of a member of a class template, the keyword typename is not required when referring to the unqualified name of a previously declared member
of the class template that declares a type. The keyword typename shall always be specified when the
member is referred to using a qualified name, even if the qualifier is simply the class template name.
#include <iostream>
#include <vector>
int main()
{
class Int {
public:
Int(int _i) : i(i) {}
private:
int i;
};
std::vector<Int> VI;
}
I try to compile the above code and got the following error message:
foo.cc: In function 'int main()':
foo.cc:13: error: 'main()::Int' uses local type 'main()::Int'
foo.cc:13: error: trying to instantiate 'template<class _Alloc> class std::allocator'
foo.cc:13: error: template argument 2 is invalid
foo.cc:13: error: invalid type in declaration before ';' token
Could anyone of you tell me why I can't do things like this in C++? Thanks in advance.
The standard explictly prohibits using local classes to instantiate templates in 14.3.1[temp.arg.type]/2.
A local type, a type with no linkage, an unnamed type or a type compounded from any of these types shall not be used as a template-argument for a template type-parameter.
This will be changed in C++0x.