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.
Related
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 code is not valid:
struct base {
};
struct inherit : const base {
};
You cannot inherit from a const type.
Does the situation change when templates are involved? In other words, is this code valid:
struct base {
};
template<typename T>
struct inherit : T {
using T::T;
};
int main() {
inherit<base const>{};
}
gcc is says it is fine, but clang reports
<source>:6:2: error: 'const base' is not a direct base of 'inherit<const base>', cannot inherit constructors
using T::T;
^ ~
<source>:10:2: note: in instantiation of template class 'inherit<const base>' requested here
inherit<base const>{};
^
1 error generated.
Compiler returned: 1
To make clang happy, I need to do something like this:
template<typename T>
struct inherit : T {
using U = std::remove_const_t<T>;
using U::U;
};
Which version is correct? Or are neither of them correct and I need to inherit from std::remove_const_t<T>?
Thanks to #T.C. we have:
According to [temp.param]/3:
A type-parameter whose identifier does not follow an ellipsis defines its identifier to be a typedef-name (if declared with class or typename) ... in the scope of the template declaration.
So it works just like a typedef.
And then [class.name]/5:
If a typedef-name that names a cv-qualified class type is used where a class-name is required, the cv-qualifiers are ignored.
Hence GCC is right, const should be stripped when inheriting from T, since a class-name is required at that point, as well as in the using T::T; inheriting constructors declaration.
I'm trying to use templates, but couldn't understand what is wrong with below code.
solve.h
#include "nlp.h"
#include "Ipopt_solve.h"
enum algo_type {IPOPT =1, SQP};
template<int ALG>
class solve
{
public:
solve()
{
}
};
template<>
class solve<IPOPT>
{
public:
solve(nlp*);
private:
Ipopt_solve m_ipopt;
};
solve.cpp
template<>
solve<IPOPT>::solve(nlp* problem): m_ipopt(problem)
{
}
Ipopt_solve is a sub-class of an abstract class TNLP. Ipopt_solve is initialized with a reference to nlp class.
from main.cpp
nlp problem(&model);
solve<IPOPT> solution(&problem);
I'm getting the error like shown below.
error: template-id 'solve<>' for 'solve<1>::solve(nlp*)' does not match any template declaration
solve::solve(nlp* problem): m_ipopt(problem)
This declaration in its original form
template<>
solve<IPOPT>::solve(nlp* problem): m_ipopt(problem)
{
}
is formally valid by itself. However, it is not doing what you think it is doing. This declaration declares an explicit specialization for a member of the main template
template<int ALG>
class solve
{
...
It has no relation to your explicit specialization
template<>
class solve<IPOPT>
{
...
The compiler is trying to specialize constructor solve<ALG>::solve(nlp* problem) of the main template. However, the main template has no such constructor. Hence the error message, that tells you exactly that: the compiler does not understand what constructor you are trying to specialize, it cannot find the matching member in the main template.
For example, you can use this syntax to explicitly specialize the default constructor of the main template
template<>
solve<SQP>::solve()
{
// Specialized code for `solve<SQP>`'s default constructor
}
This will compile fine since the main template does indeed have such constructor. (Note that you don't have to explicitly specialize the whole class for that, you can just explicitly specialize the constructor.)
Your intent was, obviously, completely different: to provide definition for the constructor in the class template specialization
template<>
class solve<IPOPT>
{
...
The proper syntax for that should not mention template<>
solve<IPOPT>::solve(nlp* problem): m_ipopt(problem)
{
}
You should remove template<>, i.e.
// template <>
solve<IPOPT>::solve(nlp* problem): m_ipopt(problem)
{
}
template<> is used for template specialization (for a template); but you're just defining a non-template member function (of a class template specialization). (That's why the compiler complains that the template declaration can't be found.)
So I am writing a particle accelerator code for a c++ class, and Im having trouble with the initial class set up Im being asked to use. The professor wants us to use templates for the class, but when I try to implement them, I receive a number of errors. For instance:
#include <iostream>
#include <cmath>
using namespace std;
template <class Type>
class ThreeVector {
private:
Type mx;
Type my;
Type mz;
public:
ThreeVector();
ThreeVector(Type x=0, Type y=0, Type z=0);
};
ThreeVector<Type>::ThreeVector() {
Type mx=0;
Type my=0;
Type mz=0;
}
ThreeVector<T>::ThreeVector(Type x, Type y, Type z) {
mx=x;
my=y;
mz=z;
}
is part of my header file (the class is required to be in a header file). When I run my program (can provide if needed), it gives me the following errors:
ThreeVector.h:30:13: error: ‘Type’ was not declared in this scope
ThreeVector.h:30:17: error: template argument 1 is invalid
ThreeVector.h: In function ‘int ThreeVector()’:
ThreeVector.h:30:32: error: ‘int ThreeVector()’ redeclared as different kind of symbol
ThreeVector.h:6:7: note: previous declaration ‘template class ThreeVector’
ThreeVector.h:31:2: error: ‘Type’ was not declared in this scope
ThreeVector.h:32:7: error: expected ‘;’ before ‘my’
ThreeVector.h:33:7: error: expected ‘;’ before ‘mz’
ThreeVector.h: At global scope:
ThreeVector.h:35:13: error: ‘Type’ was not declared in this scope
These problems did not exist before I started using the template, i.e., if I explicitly define all variable types, my class works fine. So, Im not really sure what is wrong with my template definition? If anyone could help, Id be really appreciative.
Thanks!
You have to declare template arguments for methods that are part of a template class and yet are defined outside of the class definition. So to make your function definitions you have to do this:
template<class Type>
ThreeVector<Type>::ThreeVector() {
mx=0;
my=0;
mz=0;
}
template<class Type>
ThreeVector<T>::ThreeVector(Type x, Type y, Type z) {
mx=x;
my=y;
mz=z;
}
This is because the templated type is not available to the method declarations when they are outside of the class definition. To fix this you have to add a template< ... > with the same arguments as for the original class.
Also, you should use initializer lists to initialize members. That would make your constructors look like this:
template<class Type>
ThreeVector<Type>::ThreeVector() :
mx(0),
my(0),
mz(0)
{
}
You forgot to add
template <typename Type>
Before the function definition.
Remove Type from the body of the function. When you add Type, you are declaring three function variables that are not related to the class members.
template <typename Type>
ThreeVector<Type>::ThreeVector() {
mx=0;
my=0;
mz=0;
}
You can make it better by initializing the member using the initializer list syntax:
template <typename Type>
ThreeVector<Type>::ThreeVector() : mx(0), my(0), mz(0) { }
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.