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
Related
This doesn't compile:
template<class X> struct A {
template<int I> void f() {}
};
template<class T> void g()
{
A<T> a;
a.f<3>(); // Compilation fails here (Line 18)
}
int main(int argc, char *argv[])
{
g<int>(); // Line 23
}
The compiler (gcc) says:
hhh.cpp: In function 'void g()':
hhh.cpp:18: error: expected primary-expression before ')' token
hhh.cpp: In function 'void g() [with T = int]':
hhh.cpp:23: instantiated from here
hhh.cpp:18: error: invalid use of member (did you forget the '&' ?)
Can anyone explain why this is? Is there a way to get it to work?
Try the following code:
template<class T> void g()
{
A<T> a;
a.template f<3>(); // add `template` keyword here
}
According to C++'03 Standard 14.2/4:
When the name of a member template specialization appears after . or -> in a postfix-expression, or after nested-name-specifier in a qualified-id, and the postfix-expression or qualified-id explicitly depends on a template-parameter (14.6.2), the member template name must be prefixed by the keyword template. Otherwise the name is assumed to name a non-template.
Future C++ Standard seems to be still require this keyword according to draft n2857 14.3/4. Some compilers has special mode that allows to compile original code without errors (Comeau compiles it in so called relaxed mode).
I would like to pass a function pointer from an array of function pointers as a template argument. My code seems to compile using MSVC even though Intellisense complains that something is wrong. Both gcc and clang fail to compile the code.
Consider the following example:
static void test() {}
using FunctionPointer = void(*)();
static constexpr FunctionPointer functions[] = { test };
template <FunctionPointer function>
static void wrapper_function()
{
function();
}
int main()
{
test(); // OK
functions[0](); // OK
wrapper_function<test>(); // OK
wrapper_function<functions[0]>(); // Error?
}
MSVC compiles the code but Intellisense gives the following error: invalid nontype template argument of type "const FunctionPointer"
gcc fails to compile with the following message:
<source>: In function 'int main()':
<source>:19:33: error: no matching function for call to 'wrapper_function<functions[0]>()'
19 | wrapper_function<functions[0]>(); // Error?
| ^
<source>:8:13: note: candidate: 'template<void (* function)()> void wrapper_function()'
8 | static void wrapper_function()
| ^~~~~~~~~~~~~~~~
<source>:8:13: note: template argument deduction/substitution failed:
<source>:19:30: error: '(FunctionPointer)functions[0]' is not a valid template argument for type 'void (*)()'
19 | wrapper_function<functions[0]>(); // Error?
| ~~~~~~~~~~~^
<source>:19:30: note: it must be the address of a function with external linkage
clang fails to compile with the following message:
<source>:19:2: error: no matching function for call to 'wrapper_function'
wrapper_function<functions[0]>(); // Error?
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
<source>:8:13: note: candidate template ignored: invalid explicitly-specified argument for template parameter 'function'
static void wrapper_function()
^
1 error generated.
Questions:
Is wrapper_function<functions[0]>(); valid or not?
If it isn't, is there anything I can do to pass functions[0] as a template argument to wrapper_function? My goal is to construct a new array of function pointers at compile time, with the content { wrapper_function<functions[0]>, ..., wrapper_function<functions[std::size(functions) - 1]> }.
Expression wrapper_function<functions[0]>(); is forbidden because of the following:
14.3.2 Template non-type arguments [temp.arg.nontype]
A template-argument for a non-type, non-template template-parameter
shall be one of:
[...]
— a constant expression (5.19) that designates the address of an
object with static storage > duration and external or internal linkage
or a function with external or internal linkage, including function
templates and function template-ids but excluding non-static class
members, expressed (ignoring parentheses) as & id-expression, 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; [...]
It is forbidden to use pointers as non-type template arguments other than of the form &id so, basically, following would work:
static void test() {}
using FunctionPointer = void(*)();
static constexpr FunctionPointer functions[] = { test };
template <FunctionPointer function>
static void wrapper_function()
{
function();
}
int main()
{
test(); // OK
functions[0](); // OK
wrapper_function<test>(); // OK
wrapper_function<&test>(); // OK
}
and following snippet won't work when compiled with C++14 option:
constexpr auto func = &test;
wrapper_function<func>();
When compiled with C++17 option, your approach and the one above would both work:
int main()
{
test(); // OK
functions[0](); // OK
wrapper_function<test>(); // OK
wrapper_function<&test>(); // OK
wrapper_function<func>(); // OK
wrapper_function<functions[0]>(); // OK
}
See live
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>(); }
#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.
This doesn't compile:
template<class X> struct A {
template<int I> void f() {}
};
template<class T> void g()
{
A<T> a;
a.f<3>(); // Compilation fails here (Line 18)
}
int main(int argc, char *argv[])
{
g<int>(); // Line 23
}
The compiler (gcc) says:
hhh.cpp: In function 'void g()':
hhh.cpp:18: error: expected primary-expression before ')' token
hhh.cpp: In function 'void g() [with T = int]':
hhh.cpp:23: instantiated from here
hhh.cpp:18: error: invalid use of member (did you forget the '&' ?)
Can anyone explain why this is? Is there a way to get it to work?
Try the following code:
template<class T> void g()
{
A<T> a;
a.template f<3>(); // add `template` keyword here
}
According to C++'03 Standard 14.2/4:
When the name of a member template specialization appears after . or -> in a postfix-expression, or after nested-name-specifier in a qualified-id, and the postfix-expression or qualified-id explicitly depends on a template-parameter (14.6.2), the member template name must be prefixed by the keyword template. Otherwise the name is assumed to name a non-template.
Future C++ Standard seems to be still require this keyword according to draft n2857 14.3/4. Some compilers has special mode that allows to compile original code without errors (Comeau compiles it in so called relaxed mode).