I have a simple and reproducible code, which looks like so:
template <typename T>
class Proxy {
private:
Wrap<T> &self; // If I comment this, it will work
public:
Proxy() {}
};
template <typename T>
class Wrap {
T *p;
public:
Proxy<T> foo() {
return Proxy<T>();
}
};
int main()
{
return 0;
}
The error I get is:
'Wrap' does not name a type
If I comment Wrap<T> &self, then it will work, but this is not what I need. I need Wrap<T> to be a member of Proxy class. How can I achieve this?
You could add forward declaration of Wrap before the class definition of Proxy, otherwise the compiler can't know that it's the name of a class template. It's worth noting that reference data member doesn't require the type to be complete type, so forward declaration is enough here.
// forward declaration
template <typename T>
class Wrap;
template <typename T>
class Proxy {
private:
Wrap<T> &self;
public:
Proxy() {}
};
BTW the following issue would be that the reference data member self is not initialized.
LIVE of Clang
error: constructor for 'Proxy' must explicitly initialize the reference member 'self'
You need to add a forward declaration:
template<class T> class Wrap;
template <typename T>
class Proxy {
private:
Wrap<T> &self;
public:
Proxy() {}
};
template <typename T>
class Wrap {
T *p;
public:
Proxy<T> foo() {
return Proxy<T>();
}
};
int main()
{
return 0;
}
The code is just copied from the OP's question. But you still need to pay a attention to member Wrap<T> &self. As a reference, it should be initialized in constructor.
Related
How can I define different struct members for different template parameters? I've tried to use the requires keyword the following way:
template<typename T> requires std::is_void_v<T>
class Foo
{
public:
void Bar()
{
}
};
template<typename T>
class Foo
{
public:
T* Bar()
{
if (!m_T)
m_T = new T();
return m_T;
}
private:
T* m_T{};
};
But this does not compile:
Foo<T> Foo(void): could not deduce template argument for T
Foo<T> Foo(Foo<T>): expects 1 argument - 0 provided
Foo: requires clause is incompatabile with the declaration
Is this behaviour even possible in C++ 20?
While requires may be useful in general, its advantages for exactly matching one template parameter type are outweighed by the negatives.
Template specialization of types has been possible since C++03, maybe even C++98:
template<typename T>
class Foo;
template<>
class Foo<void>
{
public:
void Bar()
{
}
};
template<typename T>
class Foo
{
public:
T* Bar()
{
if (!m_T)
m_T = new T();
return m_T;
}
private:
T* m_T{};
};
In order to use concepts, you should still follow the same overall pattern:
Declare the template
Define the primary and all specialized bodies for the template
Example assuming my_is_magic_v is a fancier concept, not just a single particular type.
template<typename T>
class Foo;
template<typename T> requires my_is_magic_v<T>
class Foo<T>
{
public:
void Bar()
{
}
};
template<typename T>
class Foo
{
public:
T* Bar()
{
if (!m_T)
m_T = new T();
return m_T;
}
private:
T* m_T{};
};
Regarding the third error:
You cannot declare two primary class templates with the same name in the same scope. You can only declare one primary template and then add partial or explicit specializations for it. Partial specializations need to be more specialized than the primary template.
The syntax for a partial specialization is slightly different than what you are using (the syntax for primary templates) and a declaration of the primary template must precede the partial specialization:
// primary class template
template<typename T>
class Foo
{
public:
T* Bar()
{
if (!m_T)
m_T = new T();
return m_T;
}
private:
T* m_T{};
};
// partial specialization with (more) constraints
template<typename T> requires std::is_void_v<T>
class Foo<T> // <- Additional template argument list for partial specialization
{
public:
void Bar()
{
}
};
The other error messages are either a consequence of this issue as well or caused by a problem with how the template is used somewhere else that you are not showing.
I try to create a templated class, which saves the template argument as a member variable (msg_).
Now the input of the class should allow normal types like int and shared_ptr<int>.
template <typename T>
class Foo {
public:
Foo<T>() {};
private:
T msg_;
};
My problem is if the class gets initialized with shared_ptr<int>, the shared_ptr has to get initialized:
this->msg_ = std::make_shared<T*>();
I tried to solve it like this:
Foo<T>() {
if (std::is_pointer<T>::value) {
this->msg_ = std::make_shared<T*>();
}
};
, but the problem is that is has to be solved on compile time. Otherwise I can not compile.
Do you know any patterns, which solve this issue?
Thank you! and
Best regards
Fabian
You might have specialization
template <typename T>
class Foo {
public:
Foo() {}
private:
T msg_;
};
template <typename T>
class Foo<std::shared_ptr<T>>
{
public:
Foo() : msg_(std::make_shared<T>()) {}
private:
std::shared_ptr<T> msg_;
};
or create function to initialize (with overload)
template <typename> struct tag{};
template <typename T>
T foo_default_init(tag<T>) { return {}; }
template <typename T>
std::shared_ptr<T> foo_default_init(tag<std::shared_ptr<T>>)
{
return std::make_shared<T>();
}
template <typename T>
class Foo {
public:
Foo() : msg_(foo_default_init(tag<T>{})){}
private:
T msg_;
};
I want to derive a type Test from a templated type Base which I specialise on the derived type (i.e. Base<Test>).
Inside the templated type, I want to make use of a typedef defined in the derived type (the template parameter).
However, I get this compile error:
error C2039: 'X' : is not a member of 'Test'
Here is the code snippet:
template <typename T>
class Base
{
protected:
void func(typename T::X x) {}
};
class Test : public Base<Test>
{
public:
typedef int X;
};
Is this doable, and if so, what is the fix I need to make?
(I see a couple of answers for this kind of problem but it looks like my scenario isn't fixed by prefixing typename - is it something to do with deriving from a template specialised with the derived type?)
Alternatively to the typedef, you can also declare the type as second template argument in the base class:
template <typename T, typename X>
class Base
{
protected:
void func(X x) {}
};
class Test : public Base<Test, int>
{
public:
// typedef int X;
};
You have a circularity which cannot be resolved with forward declarations. But this will work, although (I suspect) not quite so strongly defined as you wanted.
template <typename T>
class Base
{
protected:
template<typename Y>
void func(Y x) {}
};
class Test : public Base<Test>
{
public:
typedef int X;
};
If func were public, then you could then write
Test t;
Test::X x;
t.func(x)
which is satisfactory for any use of the Curiously Recurring Template Pattern I think of.
This works for me:
template <typename T> struct Traits;
template <typename Derived>
class Base
{
protected:
void func(typename Traits<Derived>::X x) {}
};
class Test;
template <> struct Traits<Test>
{
typedef int X;
};
class Test : public Base<Test>
{
};
I'm not sure about this behavior, maybe someone can clarify it. But as I understand by the moment you do : public Base<Test> the type name X doesn't exists (since is declared below).
If you create a wrapper class before making the inheritance the type would exists by the moment you do the inheritance and the template instantiation will work.
This compiles with VC++ 2013
template <typename T>
class Base
{
protected:
void func(typename T::X x) {}
};
class TestWrapper
{
public:
typedef int X; //Declared, now it exists for the compiler
};
class Test
:public Base<TestWrapper> //Compiles correctly
{
};
I have a class template
template <class T>
class A
{
};
and very strange specialization
template <>
class A<class T*> : private A<void *>
{
};
Can anybody explain the meaning of this construction ?
The obfuscation declares a class T and specialize the template for T*
#include <iostream>
template <class T>
class A
{
public:
static void f() { std::cout << "Template" << '\n'; }
};
// Declare a class T and specialize the template for T*
template <>
class A<class T*> : private A<void *>
{
public:
static void f() { std::cout << "Specialization" << '\n'; }
};
class T {};
int main()
{
// Template
A<int*>::f();
// Specialization
A<T*>::f();
}
I think that the intended code would be:
template <class T>
class A<T *> : public A<void*>
{
};
That is a partial specialization that will be used for any pointer type, instead of the generic one. That is, any time A is instantiated using a pointer type, it will use this declearation instead of the generic one.
Naturally you need to instantiate, or otherwise spezialize the A<void*>, before this declaration, or else you will have an infinite recursion:
template class A<void*>;
This is a somewhat common idiom to force the compiler to reuse code. That is, you know that every instance of A<T*> is basically the same, as all pointers will behave identically under the hood. So you provide the full instantiation of A<void*> and then any other A<T*> inherits from it, doing the casts inline where needed.
Since A<T*> inherits from A<void*> it does not need to provide the bulk of the class code in its instantiation. Smaller code will hopefully will yield better performance.
Full example ahead, untested:
template <typename T>
class A
{
public:
A()
:m_data(0)
{}
void set(T x)
{ m_data = x; }
T get()
{ return m_data; }
//here there will be more complex operations
private:
T m_data;
//and a lot of data depending on T
};
template class A<void*>; //splicit instantiation
template <typename T>
class A<T*> : public A<void*>
{
private:
typedef A<void*> base_type;
public:
//only the public, and maybe protected, functions are needed
//but the implementation is one-line each
void set(T *x)
{ base_type::set(x); }
T *get()
{ return static_cast<T*>(base_type::get()); }
};
If I have a class which takes variadic pack of template arguments how can I declare them all to be friends?
Here is what I would like to do in pseudo-code form:
template<typename... Ts>
class AbstractMyClass {
int privateInt;
friend Ts...;
};
class OtherClass;
using MyClass = AbstractMyClass<OtherClass>;
class OtherClass {
public:
void foo(MyClass &c){
c.privateInt = 42;
}
};
This can only be done using "compile time recursion", much like tuples. The gist is (I am on a small laptop right now and by no means able to comfortably type):
template<class .... THINGS> class object;
template<class T> class object {
friend T;
};
template<class T,class ... THINGS>
class object: public object<THINGS> {
friend T;
};
If C++ doesn't like that, try template<> class object<> {}; as the one that ends the recursion (I terminate it with an object in 1 template paramater)
(Thanks to Dietmar Kuhl for formatting)