I know the title is a little confusing but I will try to explain what I mean.
So, think you have a class Foo and it has some template variables. It is something like :
class A
{
public:
A();
~A();
};
template <class T>
class Foo
{
public:
//These are my constructors.
Foo();
Foo(T);
Foo(T*, int); //This is for something else.
T var;
}
But in main function, I want to have something like this :
Foo<Foo<A>> multiFoos;
And Visual Studio says
"no default constructor exists for Foo<Foo<A>>"
So, I hope my question is quite clear and you can help me with this.
Thanks,
Related
Hello template wizards,
I have been concocting a utility template which has one problem left to be solved, but cannot seem to figure it out. The code in this post is a simplification of the code in question, which exhibits the same issue.
Suppose you have a template specialisation as shown below.
enum class Pets { Dog, Cat, Bird };
template <Pets variant>
class Animal;
template <>
class Animal<Pets::Cat> {
void Sound();
};
template <>
class Animal<Pets::Dog> {
void Sound();
};
template <>
class Animal<Pets::Bird> {
void Sound();
};
void Animal<Pets::Cat>::Sound() { printf("Meow!\n"); }
void Animal<Pets::Dog>::Sound() { printf("Woof!\n"); }
void Animal<Pets::Bird>::Sound() { printf("Peep!\n"); }
And then I ruin everything by saying that I might not declare the specialisation of Animal<Pets::Bird>. The latter definition of ::Sound() will fail to compile, as the type doesn't exist. Now, this seems to beg for a SFINAE solution, to me, as we have an unwanted method implementation of a type that we don't want to exist.
I'd like the compiler to simply ignore that last method definition instead of failing compilation, without changing the method signature — that is, I don't want to make the method itself a template.
Do you have any suggestions on how to make this work?
You can’t do this: SFINAE is about overload resolution, and while it also supports the very similar case of selecting a partial specialization, it’s not a general conditional compilation technique. You can use the preprocessor, of course, and you can do tricks like declaring the unwanted function private so that it “doesn’t exist”, but you can’t define a function that just is never mentioned.
I did manage to conjure up a solution, which quite neatly just declares a catch-all, for those types are to be discarded — not quite what I asked for, but closer toward the goal.
This, at least, takes care of the definitions of methods that would otherwise fail compilation.
enum class Pets { Dog, Cat, Bird };
static constexpr Pets kChosenPet = Pets::Cat;
struct AbstractAnimal {
virtual void Sound() = 0;
};
template <Pets variant = kChosenPet, bool B = (variant == kChosenPet)>
struct Animal : public AbstractAnimal {
void Sound();
};
template <Pets variant>
struct Animal<variant, true> : public AbstractAnimal {
void Sound();
};
template <>
void Animal<Pets::Cat>::Sound() {
printf("Meow!\n");
}
template <>
void Animal<Pets::Dog>::Sound() {
printf("Woof!\n");
}
template <>
void Animal<Pets::Bird>::Sound() {
printf("Peep!\n");
}
May be I don't understand something in your question. But what's wrong with just moving declaration of Sound() to Animal?
#include <stdio.h>
#include <type_traits>
enum class Pets { Dog, Cat, Bird };
template <Pets variant>
class Animal {
void Sound();
};
template<>
void Animal<Pets::Cat>::Sound() { printf("Meow!\n"); }
template<>
void Animal<Pets::Dog>::Sound() { printf("Woof!\n"); }
template<>
void Animal<Pets::Bird>::Sound() { printf("Peep!\n"); }
"SFINAE" means "Substitution Failure Is Not An Error". That starts with "Subsitution", an early part of the template instantiation process. And SFINAE is only Not An Error when there are alternatives for the failed template, e.g. other function overloads.
Now in void Animal<Pets::Bird>::Sound(), there is no Substitution, so SFINAE can't apply. We can't introduce it either - the normal way is via std::enable_if, which can turn a non-template declaration into a template declaration that might or might not be instantiated. But that doesn't work - this specialization cannot be a template declaration.
This case can be simplified:
#ifdef FOO
class Foo { int bar; }
#endif
int Foo::bar() { return 1; } // Also not fixable by SFINAE, for the same reason.
I have some code that is doing the following but I don't understand what the
using BaseTypeX::BaseTypeX is actually doing in this code. The rest of it I understand so please don't explain template specialization etc.
template<typename TReturn, typename... TArgs>
class ClassX<TReturn(TArgs...)> : public Internal::ClassXImpl<TReturn, TArgs...> {
public:
using BaseTypeX = Internal::ClassXImpl<TReturn, TArgs...>;
using BaseTypeX::BaseTypeX; // what is this doing exactly?
inline ClassX() noexcept = default;
// member function
template<class TThis, class TFunc>
inline ClassX(TThis* aThis, TFunc aFunc) {
this->bind(aThis, aFunc); // note bind is implemented in the ClassXImpl class
}
It means you inherit all the constructors of Internal::ClassXImpl<TReturn, TArgs...>. A simpler example might illustrate this better:
struct Foo
{
Foo(int);
Foo(int, double);
Foo(std::string);
};
struct Bar : Foo
{
using Foo::Foo;
};
int main()
{
Bar b1(42); // OK, Foo's constructors have been "inherited"
Bar b2(42, 3.14); // OK too
Bar b2("hello"); // OK
}
Without the using Foo::Foo, you would have to declare and define all the constructors in Bar, and call the respective Foo constructor in each one of them.
It means template class ClassX inherits its base's constructors. See here for a discussion on the topic.
second template question of the day, what a n00b:
I have a template class:
template <class T>
class foo{
private:
//...
T SubFoo;
//...
};
I also have a class called myClass. I would like to have objects of the kind:
foo<myClass> myObject;
But, and here's the problem, I would like to be able to get a pointer to myObject from myObject.SubFoo. That means that one of the members of the class myClass should be an instantiation of the template class foo.
So I can do:
class myClass{
//...
foo<myClass>* point2myClass;
}
However, it seems that this does not work because
./foo.h:103: error: ‘foo::SubFoo’ has incomplete type
When defining myClass, the program finds the line
foo<myClass>* point2myClass;
It goes to the defintion of foo and it finds:
T SubFoo;
but T, in this case myClass, has not yet been defined (that is what the program was doing!), so it doesn't know what T is, hence the error.
If I interchange the order of declarations, it will also fail because "foo" will not be defined.
How can I make this work??
Thanks a million!
The following code, should definitely work just fine. If your code is different, please specify where.
template < typename T >
struct A
{
T x;
};
struct X
{
A<X>* x;
};
int main()
{
X a;
}
What's wrong with this code? gcc 4.6.1 is complaining "‘foo’ was not declared in this scope" in baz(). If I transform the code so that one of the templates is just a regular class, the problem goes away.
struct Foo {
char foo;
};
template<int N>
struct Bar : public Foo
{
Bar() { foo; }
};
template<int N>
struct Baz : public Bar<N>
{
void baz() { foo; }
};
int main() {
Baz<10> f;
return 0;
}
What is wrong, according to the specifications, I don't know, but you may make your code to compile by using:
void baz() { Bar<N>::foo; }
foo is a dependent name; that is, it depends on the template parameter, so until the template is instantiated the compiler doesn't know what it is. You have to make it clear that it is a class member, either Bar<N>::foo or this->foo.
(You probably also want to do something with it; simply using it as the ignored value of an expression doesn't do anything at all).
This question already has answers here:
Closed 12 years ago.
Possible Duplicate:
Making an undefined class as friend, and defining it later.
I have the following code
template<typename T>
class A
{
class B;
B b;
};
int main()
{
return 0;
}
The code doesn't emit any error because A is not instantiated. Am I right?
But have a look at the second code sample
template<typename T>
class A
{
protected:
class a
{
int x;
int y;
private:
friend class b;
};
template <typename U > class b
{
int z;
U y;
};
};
int main()
{
A<int> a;
return 0;
}
In this case A is instantiated but b is not. So the code shouldn't emit any error, right? But I get a redeclaration error in msvc++2008 professional edition. It compiles fine on gcc.
What could be the reason for the error?
Sorry everyone. After reading the comments and after seeing my original code I see that I made a mistake while typing the second code sample.
I missed the definition of the constructor and the statement a *object = new a; inside the constructor. Apologies. That means my code is exactly similar to the other code posted by the other user. But now I cannot delete my question now because of the existing answers.
Regarding you second code snippet ...
template<typename T>
class A
{
protected:
class a
{
int x;
int y;
private:
friend class b;
};
template <typename U > class b
{
int z;
U y;
};
};
int main()
{
A<int> a;
return 0;
}
... it is most probably invalid code, because a very similar code snippet posted by you earlier, in the SO question "Making an undefined class as friend, and defining it later", is invalid. But I'm not sure about this.
The difference wrt. your earlier question is only that in that other question the nested class a is used, hence, instantiated.
However, the redeclaration error that you get with MSVC 8.0 does not necessarily mean that that compiler recognizes the code as invalid standard C++. It might be a compiler bug that just by happenchance causes it to (probably) correctly identify the code as invalid. And it might just be that the above code, not using a, is valid…
So, it's pretty subtle, it's language lawyer stuff.
Best advice is to just stay well clear of these rather dark corners of the language.
EDIT: the earlier question was not Pavel's (but it's the same code); see comments.
Cheers & hth.,
Class a doesn't has an access to the members of the enclosing class according to the current Standard §11.8. But the Standard has a defect report to this. So some compilers works according to the original Standard, and the others according to the proposed resolution of the defect report.
MSVC requires the full template decl for friend template classes, MSDN has an example here, specifically the bottom example:
template <class T>
class X
{
private:
T* data;
void InitData(int seed) { data = new T(seed); }
public:
void print() { cout << *data << endl; }
template <class U> friend class Factory;
};
template <class U>
class Factory
{
public:
U* GetNewObject(int seed)
{
U* pu = new U;
pu->InitData(seed);
return pu;
}
}
so yours should declare:
template <typename U > friend class b;
The code doesn't emit any error
because A is not instantiated. Am I
right?
I am not sure, but I don't think so. A compiler which emits an error is also equally standards conformant as a compiler which does not.
The below quote along with the example that immediately follows is a proof of this to my mind
$14.6/7 - "[Note: if a template is
instantiated, errors will be diagnosed
according to the other rules in this
Standard. Exactly when these errors
are diagnosed is a quality of
implementation issue. ]"