I have the following (admittedly contrived) code that compiles just fine in gcc 6, but doesn't compile in gcc 7. Notice the use of an undeclared constructor in the definition of bar. This should print an error if the function is ever referenced elsewhere in the code (uncommenting foo.bar() causes gcc 6 to print an error). However, gcc 7 prints an error even if the function is not used.
Some changes cause the code to also compile with gcc 7 (e.g. if B is replaced with T in the definition of A), while some changes cause it to fail with gcc 6 (e.g. if this-> is not used). What's going on here? When does gcc decide to compile unused template code? Do different versions of gcc use different rules to decide?
struct B {};
template <typename T>
struct A {
B* bar()
{
// undeclared constructor
return new B(this->b);
}
B* b;
};
int main (int argc, char* argv[])
{
A<int> foo;
//foo.bar();
}
A::bar() is a non-template member function in a template class. If it were itself a template, SFINAE would allow the code to compile when bar() is not called. But the way you have it now, once A is instantiated with some template arguments, all of it is expected to be valid.
One solution would be:
template <typename T>
struct A {
template <typename X>
X* bar()
{
// static_assert(is_same<X, B>) if you want
return new X(this->b);
}
B* b;
};
Then you'd call a.bar<B>() instead of a.bar(), and if you don't call it, it won't be instantiated and won't cause an error.
Perhaps I'm missing something, but you appear to be trying to construct a B object from a B pointer. And there is no default constructor that does that. So surely you want:
struct B {
B( B * b ) {
}
};
Related
This question already has answers here:
Why do I have to access template base class members through the this pointer?
(3 answers)
Closed 5 years ago.
Consider the following code:
template<class T> class Foo
{
public:
Foo() { a = 1; }
protected:
int a;
};
template<class T> class Bar : public Foo<T>
{
public:
Bar() { b = 4; };
int Perna(int u);
protected:
int b;
};
template<class T> int Bar<T>::Perna(int u)
{
int c = Foo<T>::a * 4; // This works
return (a + b) * u; // This doesn't
}
g++ 3.4.6, 4.3.2 and 4.1.2 give error
test.cpp: In member function `int Bar<T>::Perna(int)':
test.cpp:25: error: `a' was not declared in this scope
g++ 2.96 and MSVC 6, 7, 7.1, 8 and 9 accept it, as do (at least) older Intel and SGI c++ compilers.
Do the new Gnu C++ compiler obey the standard or not? If they do, what is the rationale behind that inheriting class is not able to see a protected inherited member variable?
Also, if there's
int A() { return a; }
in Foo, I get error
test.cpp:25: error: there are no arguments to A that depend on a template parameter, so a declaration of A must be available
test.cpp:25: error: (if you use -fpermissiveâ, G++ will accept your code, but allowing the use of an undeclared name is deprecated)
when I try to use it in a member function of Bar.
I find that curious as well: Bar inherits Foo, so I think it's obvious that A() in scope of Bar is Foo::A().
The later GCC versions correctly implement the standard.
The standard specifies that unqualified names in a template are non-dependent and must be looked up when the template is defined. The definition of a dependent base class is unknown at that time (specializations of the base class template may exist) so unqualified names are unable to be resolved.
This is true for both variable and function names declared in the base class.
As you have observed the solution is to provide the qualified name of the variable or function, or to provide a "using" declaration. E.g.
template<class T>
int Bar<T>::Perna(int u)
{
int c = Foo<T>::a * 4; // This works
c = this->a * 4; // and this
using Foo<T>::a;
c = a * 4; // and with 'using', so should this
}
(I'm actually not 100% sure about the correct syntax for the using version and can't test from here, but you get the idea).
The error message that GCC gives shows that your version of GCC still had a bug that is only resolved in GCC4.7 trunk versions. Older versions, including GCC4.1 will happily accept following code
template<typename T>
struct A {
void f(int) { }
};
template<typename T>
struct B : A<T> {
void g() { T t = 0; f(t); }
};
int main() {
B<int> b; b.g();
}
GCC will look up f in f(t) within the base class A<T> and will find the declaration in the base class. GCC does that because f is dependent, because there are arguments to f that "depend on a template parameter" (look at its error message it gave you!). But the Standard forbids GCC to do that for two reasons
The Standard says that use of unqualified names will never find a declaration in a dependent base class no matter whether the name is dependent.
The Standard says that dependent lookup of a function name at instantiation time will only do ADL.
GCC 4.7 implements the Standard correctly in that regard.
I have a class template that assigns a unique_ptr to nullptr using an in-class member initializer. If I use MyClass(){}, all is well. If I use MyClass() = default, I get:
conversion from 'std::nullptr_t' to non-scalar type 'std::unique_ptr<A>' requested
Here is a minimal example which fails to compile with g++ 4.8.4:
#include <memory>
class A{};
template <typename T>
class Test
{
std::unique_ptr<A> data = nullptr;
public:
//Test() {} // works fine
Test() = default; // compiler error
};
int main()
{
Test<float> test;
}
Any ideas?
As pointed out in the comments already, this is a compiler bug. It's not a problem in the library implementation of unique_ptr, but a language issue that is fully reproducable without any standard library headers, seemingly only in class templates:
struct A { A(int); };
struct B { A a = 1; };
B b; // ok
template <typename T> struct C { A a = 1; };
C<void> c; // error
Luckily, it's a compiler bug that you can work around. The implicit conversion is mishandled. Force an explicit conversion and even GCC 4.8 accepts it. In your case, that means:
std::unique_ptr<A> data = std::unique_ptr<A>(nullptr);
This question already has answers here:
Why do I have to access template base class members through the this pointer?
(3 answers)
Closed 5 years ago.
Consider the following code:
template<class T> class Foo
{
public:
Foo() { a = 1; }
protected:
int a;
};
template<class T> class Bar : public Foo<T>
{
public:
Bar() { b = 4; };
int Perna(int u);
protected:
int b;
};
template<class T> int Bar<T>::Perna(int u)
{
int c = Foo<T>::a * 4; // This works
return (a + b) * u; // This doesn't
}
g++ 3.4.6, 4.3.2 and 4.1.2 give error
test.cpp: In member function `int Bar<T>::Perna(int)':
test.cpp:25: error: `a' was not declared in this scope
g++ 2.96 and MSVC 6, 7, 7.1, 8 and 9 accept it, as do (at least) older Intel and SGI c++ compilers.
Do the new Gnu C++ compiler obey the standard or not? If they do, what is the rationale behind that inheriting class is not able to see a protected inherited member variable?
Also, if there's
int A() { return a; }
in Foo, I get error
test.cpp:25: error: there are no arguments to A that depend on a template parameter, so a declaration of A must be available
test.cpp:25: error: (if you use -fpermissiveâ, G++ will accept your code, but allowing the use of an undeclared name is deprecated)
when I try to use it in a member function of Bar.
I find that curious as well: Bar inherits Foo, so I think it's obvious that A() in scope of Bar is Foo::A().
The later GCC versions correctly implement the standard.
The standard specifies that unqualified names in a template are non-dependent and must be looked up when the template is defined. The definition of a dependent base class is unknown at that time (specializations of the base class template may exist) so unqualified names are unable to be resolved.
This is true for both variable and function names declared in the base class.
As you have observed the solution is to provide the qualified name of the variable or function, or to provide a "using" declaration. E.g.
template<class T>
int Bar<T>::Perna(int u)
{
int c = Foo<T>::a * 4; // This works
c = this->a * 4; // and this
using Foo<T>::a;
c = a * 4; // and with 'using', so should this
}
(I'm actually not 100% sure about the correct syntax for the using version and can't test from here, but you get the idea).
The error message that GCC gives shows that your version of GCC still had a bug that is only resolved in GCC4.7 trunk versions. Older versions, including GCC4.1 will happily accept following code
template<typename T>
struct A {
void f(int) { }
};
template<typename T>
struct B : A<T> {
void g() { T t = 0; f(t); }
};
int main() {
B<int> b; b.g();
}
GCC will look up f in f(t) within the base class A<T> and will find the declaration in the base class. GCC does that because f is dependent, because there are arguments to f that "depend on a template parameter" (look at its error message it gave you!). But the Standard forbids GCC to do that for two reasons
The Standard says that use of unqualified names will never find a declaration in a dependent base class no matter whether the name is dependent.
The Standard says that dependent lookup of a function name at instantiation time will only do ADL.
GCC 4.7 implements the Standard correctly in that regard.
I have the next sample code that compiles with gcc (4.7.2 using -std=c++11):
template<class C>
struct template_test
{
C testing() const
{
return C();
}
};
class A;
struct test : public template_test<A> // (1)
{};
struct A
{};
int main()
{
test t;
}
At point (1) the function template_test<A>::testing() is instantiated, and use a function of A, specifically its default constructor. Therefore, test contains this instantiated function as a function member. However, at this point A is an incomplete type, and C++ prohibits you to use members of a incomplete type.
Is this a positive gcc's error or is there another explanation?
Not only is template_test::testing() not instantiated at (1), it's never instantiated in this program. Template members are only instantiated on use, and testing() isn't used. To make this more clear, change the code slightly to:
template<class C>
struct template_test
{
C testing() const
{
return C::foo();
}
};
class A;
struct test : public template_test<A> // (1)
{};
struct A
{};
int main()
{
test t;
}
which also compiles and runs fine.
That's all right. The testing() member function won't get instantiated until you will actually invoke it. To see this, try rewriting it as follows:
C testing() const
{
static_assert(C::value, "Error!");
return C();
}
You'll see that no compilation error is issued until you try to invoke the function, but the static assert will be triggered when you add t.testing() to your main() function.
In other words, your premise that "At point (1) the function template_test<A>::testing() is instantiated" is incorrect.
You are instantiating a template with an incomplete type, this is OK.
The member function testing returns an instance of an incomplete type, which is not OK (but whether or not that's OK only comes into discussion when it's instantiated). However, you never call that function, so it is never instantiated, and thus there is no error. Instantiating the structure alone (and calling its constructor/destructor) is harmless.
Therefore, GCC is correct in letting you compile that. It would fail the moment you try to call testing.
This question already has answers here:
Why do I have to access template base class members through the this pointer?
(3 answers)
Closed 5 years ago.
Consider the following code:
template<class T> class Foo
{
public:
Foo() { a = 1; }
protected:
int a;
};
template<class T> class Bar : public Foo<T>
{
public:
Bar() { b = 4; };
int Perna(int u);
protected:
int b;
};
template<class T> int Bar<T>::Perna(int u)
{
int c = Foo<T>::a * 4; // This works
return (a + b) * u; // This doesn't
}
g++ 3.4.6, 4.3.2 and 4.1.2 give error
test.cpp: In member function `int Bar<T>::Perna(int)':
test.cpp:25: error: `a' was not declared in this scope
g++ 2.96 and MSVC 6, 7, 7.1, 8 and 9 accept it, as do (at least) older Intel and SGI c++ compilers.
Do the new Gnu C++ compiler obey the standard or not? If they do, what is the rationale behind that inheriting class is not able to see a protected inherited member variable?
Also, if there's
int A() { return a; }
in Foo, I get error
test.cpp:25: error: there are no arguments to A that depend on a template parameter, so a declaration of A must be available
test.cpp:25: error: (if you use -fpermissiveâ, G++ will accept your code, but allowing the use of an undeclared name is deprecated)
when I try to use it in a member function of Bar.
I find that curious as well: Bar inherits Foo, so I think it's obvious that A() in scope of Bar is Foo::A().
The later GCC versions correctly implement the standard.
The standard specifies that unqualified names in a template are non-dependent and must be looked up when the template is defined. The definition of a dependent base class is unknown at that time (specializations of the base class template may exist) so unqualified names are unable to be resolved.
This is true for both variable and function names declared in the base class.
As you have observed the solution is to provide the qualified name of the variable or function, or to provide a "using" declaration. E.g.
template<class T>
int Bar<T>::Perna(int u)
{
int c = Foo<T>::a * 4; // This works
c = this->a * 4; // and this
using Foo<T>::a;
c = a * 4; // and with 'using', so should this
}
(I'm actually not 100% sure about the correct syntax for the using version and can't test from here, but you get the idea).
The error message that GCC gives shows that your version of GCC still had a bug that is only resolved in GCC4.7 trunk versions. Older versions, including GCC4.1 will happily accept following code
template<typename T>
struct A {
void f(int) { }
};
template<typename T>
struct B : A<T> {
void g() { T t = 0; f(t); }
};
int main() {
B<int> b; b.g();
}
GCC will look up f in f(t) within the base class A<T> and will find the declaration in the base class. GCC does that because f is dependent, because there are arguments to f that "depend on a template parameter" (look at its error message it gave you!). But the Standard forbids GCC to do that for two reasons
The Standard says that use of unqualified names will never find a declaration in a dependent base class no matter whether the name is dependent.
The Standard says that dependent lookup of a function name at instantiation time will only do ADL.
GCC 4.7 implements the Standard correctly in that regard.