What is the order of compilation for templated objects? - c++

Sorry could not find a better title for my question. Basically what I noticed was the following compiles fine:
#include <vector>
void foo();
int main () {
foo();
return 0;
}
namespace{
struct point {
double x, y;
};
}
void foo(){
std::vector<point> p;
}
whereas compiler complains about the following:
#include <vector>
void foo();
int main () {
foo();
return 0;
}
void foo(){
struct point {
double x, y;
};
std::vector<point> p;
}
// g++ output:
a.cpp: In function ‘void foo()’:
a.cpp:14: error: template argument for ‘template<class _Tp> class std::allocator’ uses local type ‘foo()::point’
a.cpp:14: error: trying to instantiate ‘template<class _Tp> class std::allocator’
a.cpp:14: error: template argument 2 is invalid
a.cpp:14: error: invalid type in declaration before ‘;’ token
I want to know what is wrong with the second approach? Isn't struct point completely defined at the point of creating a new std::vector<point> object?

This is due to a limitation in C++03 (now lifted in C++11), that simply forbids the use of local types (i.e. types defined in function bodies) as template arguments.

Related

How to call a function with default parameters when used as non-type template parameter?

This is a follow-up of this question: Passing function as a class's template paremeter with unknown type
My navie idea was that Jarod42s answer:
template <auto F>
class A{
public:
void func(){
F();
}
};
allows to use functions with default parameters as parameter to A and call them via F(). If this was possible, the above A could handle functions of arbitrary type, given all parameters have defaults.
However this fails:
void foo(int x= 0){}
double bar(int y=0,int x=0) {return 1;}
template <auto F>
class A{
public:
void func(){
F();
}
};
int main(){
A<&foo> a;
a.func();
}
with error:
<source>: In instantiation of 'void A<F>::func() [with auto F = foo]':
<source>:14:12: required from here
<source>:8:10: error: too few arguments to function
8 | F();
| ~^~
ASM generation compiler returned: 1
<source>: In instantiation of 'void A<F>::func() [with auto F = foo]':
<source>:14:12: required from here
<source>:8:10: error: too few arguments to function
8 | F();
| ~^~
Execution build compiler returned: 1
Can the above A be fixed to call foo or bar without specializing for their exact type and use their default parameters?
As has been pointed out by RemyLebeau in a comment:
Default values are not part of a function's signature. Inside of your template, the default values are lost. To do what you are attempting, you will have to wrap the function calls inside of a lambda or functor
And that actually does not require to change anything about A:
int main(){
A<[](){ return foo(); }> a;
a.func();
}
Live Demo

C++ static template class member as friend template function default parameter

Why does using static template class member as friend template function default parameter give me compile error in c++? How to slove?
Here is the code:
#include <iostream>
template<typename T>
void func(T n);
template<typename T>
class MyClass
{
private:
static T statTemp;
public:
friend void func<>(T n);
};
template<typename T>
T MyClass<T>::statTemp(1);
template<typename T>
void func(T n = MyClass<T>::statTemp)
{
std::cout << n << std::endl;
}
int main()
{
func<int>();
}
On compile:
g++ -std=c++11 main.cpp
error: redeclaration of 'template<class T> void func(T)' may not have default arguments [-fpermissive]
void func(T n = MyClass<T>::statTemp)
^~~~
In function 'int main()':
error: no matching function for call to 'func<int>()'
func<int>();
^
note: candidate: 'template<class T> void func(T)'
void func(T n = MyClass<T>::statTemp)
^~~~
note: template argument deduction/substitution failed:
note: candidate expects 1 argument, 0 provided
func<int>();
^
visual studio 2017
C2672 "func": No matching overloaded function found.
The language does not allow default arguments for template functions to be added in later declarations of a function in the same scope.
The C++17 standard draft n4659 states :
11.3.6 Default arguments [dcl.fct.default]
...
4 For non-template functions, default arguments can be added in later declarations of a function in the same scope.
Since func is a template function, it is not permitted to add default arguments in later declarations of a func in the same scope.
So GCC correctly rejects this as such:
error: redeclaration of 'template<class T> void func(T)' may not have default arguments [-fpermissive]
void func(T n = MyClass<T>::statTemp)
I got your program to compile, however, I am honestly not sure what it is I really did. I can only take my intuition through it and do the best I can to explain what I just did:
#include <iostream>
template<typename T>
void func();
template<typename T>
class MyClass
{
private:
static T statTemp;
public:
friend void func<T>();
};
template<typename T>
T MyClass<T>::statTemp(1);
template<typename T>
void func()
{
T n = MyClass<T>::statTemp;
std::cout << n << std::endl;
}
int main()
{
func<int>();
}
First, I noticed your original funct(T n) you had declared this at the top of the file and it expected a T n to be passed into the function. In main, you do no such thing. So when you call func(T n) and pass nothing into the function, the compiler gets angry since it expects something to be passed in. Maybe what you can do, is overload the function in which calls another func(T n) where you pass it T n = MyClass<T>::statTemp;
Lastly, your friend void func<>() had no template type so the compiler was angry with that as well.
I hope that helps.

Curiously recurring template pattern. No matching function for call to.. template argument/substitution failed

I am trying to implement the Curiously Recurring Template Pattern in C++, but I can't make it work. Can someone point out what is wrong with my code?
template <typename T>
struct Base {
int x;
Base():x(4){}
};
struct Derived: Base<Derived> {
Derived(){}
};
template<typename H>
void dosomething(Base<H> const& b) {
std::cout << b.x << std::endl;
}
int main() {
Derived k();
dosomething(k);
}
I am trying to keep the signature of dosomething as it is, so that any class that implements the methods in Base can be used in dosomething().
This is the error I am getting:
||=== Build: Debug in test (compiler: GNU GCC Compiler) ===|
In function ‘int main()’:
error: no matching function for call to ‘dosomething(Derived (&)())’
note: candidate: template<class H> void dosomething(const Base<H>&)
note: template argument deduction/substitution failed:
note: mismatched types ‘const Base<H>’ and ‘Derived()’
Why am I getting this error? Isn't the compiler supposed to treat k as a const reference when invoking dosomething()?
Derived k(); // function declaration
it is a function declaration, which takes no parameters and return Derived object.
And compiler error tells you about it by
no matching function for call to ‘dosomething(Derived (&)())
^^^^^^^^^^^^^
try
Derived k; // instance of object
dosomething(k);
That's the result of vexing parse. This declaration:
Derived k();
is a function. You should use Derived k; or Derived k{};.

Can auto placeholder be used to deduce function result in non-type template parameter?

Consider simple example:
template <auto(*X)()>
struct Foo {
decltype(X()) x;
};
int bar();
int main() {
static_cast<void>(Foo<bar>{});
}
Both [gcc] and [clang] seem to accept the code. Is the code really c++17 compliant? If so is there some other rule that makes the following code ill formed?
template <class T, auto(*X)(T)>
struct Foo {
decltype(X(0)) x;
};
int bar(int);
int main() {
static_cast<void>(Foo<int, bar>{});
}
This one makes only [gcc] unhappy.
Error message:
prog.cc: In function 'int main()':
prog.cc:9:35: error: unable to deduce 'auto (*)(T)' from 'bar'
static_cast<void>(Foo<int, bar>{});
^
prog.cc:9:35: note: mismatched types 'T' and 'int'
Yes, auto may be used inside a compound type ([temp.param]/4.6, [dcl.type.auto.deduct]). I believe that gcc is in error in your second example: your explicitly specified T of int is substituted before performing deduction ([temp.deduct]/2.3, /5, and /6, referenced by [dcl.type.auto.deduct]/2.3 and /4).

Can't explicitly instantiate templated function into templated class

I don't understand why the following code isn't working, why can't I explicitly instantiate the templated function? If I remove that < int > I get a "no matching function call"
#include <iostream>
using namespace std;
template <typename T>
class Xclass
{
public:
template <typename Y>
void xfunc()
{
cout << "Hello";
}
};
template<typename T2>
class Z
{
public:
void x2()
{
Xclass<T2> obj;
obj.xfunc<int>();
}
};
int main() {
Z<int> obj;
obj.x2();
return 0;
}
The error is:
prog.cpp: In member function ‘void Z<T2>::x2()’:
prog.cpp:24:15: error: expected primary-expression before ‘int’
obj.xfunc<int>();
^
prog.cpp:24:15: error: expected ‘;’ before ‘int’
Since the type of obj is a dependent type, you must use the template keyword to tell the compiler it is a template:
Xclass<T2> obj;
obj.template xfunc<int>();
See Where and why do I have to put the "template" and "typename" keywords? for a thorough explanation of when you have to use template.