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.
Related
How can I return a "B" type using a method of an "A" class? For example:
template <typename T> class A{
//something
template <typename V> class B{
//something
};
B& foo(){
B<T> y; //the variable must have the same type T of the father class (for my exercise)
//something
return y;
}
};
main:
A <int> o;
o.foo();
Once I try to compile it, it gives me these errors:
"invalid use of template-name 'A< T >::B' without an argument list" at "B& foo()..."
and
"'class A' has no member named 'foo'"
I have written the function "foo" after closing the class B, so it might be right...
There are three problems with your code:
The public access specifier is missing. foo() won't be accessible outside class A otherwise.
You need to add the template arguments to the return type as well, i.e. declare the member function as B<T> foo(). Even better, let the compiler deduce the return type (works with C++14 and beyond), so just write auto foo()
You are returning a reference to a local variable, which leads to undefined behavior. Just return the local variable as value, due to copy elision you won't need to worry about performance issues.
With that in mind, your code should work.
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 ) {
}
};
As answered here: How can an incomplete type be used as a template parameter to vector here? usage of incomplete type as template argument when instantiating a template component can result in undefined behaviour. But does that rule hold true when we have only pointer/reference to template component with incomplete type as argument? Does the instatiation happen in this case too?
For example:
// SomeAlgoInterface.hpp
#include <vector>
struct Result; // forward declaration
class SomeAlgoInterface
{
public:
virtual ~SomeAlgoInterface() = default;
public:
// the following line is definitely OK, ...
virtual void f1(const Result & result) = 0;
// ... but I'm not quite sure about the following one
virtual void f2(const std::vector<Result> & results) = 0;
};
In other words, is the code above valid or not?
The declaration is correct, so long as you don't call f2.
The compiler doesn't need to know the internal of Result class if you don't call f2. There's no storage allocation in the declaration.
If some compilation unit call f2, you need to supply the complete type for Result class, or you need another reference parameter to call f2:
void another_f(SomeAlgoInterface& i, std::vector<Result>& results)
{
i.f2(results);
}
I'm puzzled by the following problem. I want to write some trait struct in order to test if a certain class is derived from another. This can be solved with boost::is_base_of<>. However, the base class I want to test against has a free undefined template parameter.
Here is some code example:
template<typename T> class Base {};
class IntDeriv : Base<int> {};
class Foo {};
template< class TestClass >
struct is_derived_from_Base {
// how to create something that does the following and forces the compiler to deduce T
static const bool value = boost::is_base_of< Base<T> , TestClass >::value;
};
int main() {
cout << is_derived_from_Base<Foo> << endl; // should print 0
cout << is_derived_from_Base<IntDeriv> << endl; // should print 1
}
The problem is how to deduce T for Base<T> inside is_base_of.
Is this possible at all? I smell some enable_if but I'm not sure how to put it together.
What you want is possible. The trick used is possible in C++03, but as you didn't specify I will give you the C++11 version (using decltype, not available in C++03):
template<class TestClass>
struct is_derived_from_Base
{
template<typename T>
static std::true_type inherited(Base<T>*);
static std::false_type inherited(void*);
static const bool value = decltype(inherited(new TestClass()))::value;
};
You can see a live version here.
So, how does it works ?
When the struct is instantiated and value is needed, the compiler will get the return type of inherited(new TestClass()). This will call the appropriate function: if TestClass inherits Base<T>, then TestClass* (returned by new) is castable to Base<T>*, T being automatically deduced by the compiler. The return type is std::true_type. If TestClass does not inherits Base<T>, then the other overload is choosen, and the return type is std::false_type. The rest is straightforward: std::true_type::value = true and std::false_type::value = false.
There are still some corner cases:
Using private inheritance results in a compile error. I do not know how to solve it, because I don't know the answer: if A privately inherits B, is A derived from B or not ? (in general, private inheritance is considered as an implementation inheritance). Also note that in this case, A* a = new B(); will not compile.
Using a private constructor prevents the previously explained trick from working correctly. It will result in a compile-time error. Since this defeats the whole point of this method, you will have to find another way for such classes.
Note you have to use it the following way: is_derived_from_Base<Foo>::value, not as you've written (is_derived_from_Base<Foo>).
C++ templates allow we put whatever in our objects with template arguments. However, if our template arguments use functions/variables which belong to certain types, how do we check?
template<typename BarType>rguments
class Foo {
public:
Foo() { bar = new BarType() }
private:
BarType * bar;
}
Foo<Bar> …
BarType could be anything derived from a Bar superclass.
What happens if we invoke some functions which only belong to Bar in our Foo class? What happens if we pass non-BarType? Do we have anyway to check?
You will get a compile-time error if your templated code makes reference to members that the actual parameter doesn't provide when you try to instantiate the template. So don't worry, you won't be able to break anything.
Think of templates as a code-generation mechanism. Whether the generated code actually makes sense can sometimes only be determined when you actually try it.
Given the class template TempFoo below, you see that it calls the example function of the templated T type in its constructor. The first two types work because they both define example; the third doesn't.
template<typename T>
class TempFoo
{
void TempFoo() {
T obj;
obj.example();
}
};
class First {
void example() {}
};
class Second {
void example() {}
};
class Third {
};
int main()
{
TempFoo<First> f; // works
TempFoo<Second> s; // works
TempFoo<Third> t; // doesn't
}
Whatever you're giving in the tempalte parameter list is simple a place place holder. Compiler will repalce with appropriate types according to the type of object which is used to instantiate the template class. A compile-time error will be appear if the object doesn't satify the operations done in the functions. Also it's a good practice to use 'T' as place holder.
An easy way to ensure that the template parameter derives from the base class:
template<typename BarType>
class Foo
{
// ...
~Foo() { Bar* p = (BarType*)0; }
};
The compiler will type-check the assignment, generating an error if Bar isn't an unambiguous supertype of BarType, and then optimize away the unused local variable.