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()); }
};
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.
Assuming the following class:
template <typename T>
class Test {
public:
void do_something1();
...
void do_something100(); // basically many functions already defined
}
How can I add another function to a specialisation of the class while not rewriting all possibly 100 functions that are already templated?
template<>
class Test<int> {
public:
void do_something_else();
}
...
int main() {
auto x = Test<int>();
x.do_something5(); // should be still valid, would call
// Test<T>::do_something5() with T being int
x.do_something_else(); // valid because declared in specialisation
...
}
Right now, if the Test<int> specialisation is left as in the example above, it would only contain do_something_else(), without do_something1...100().
Solution
Based on the accepted answer, using the given example, I did the following:
namespace parent {
template <typename T>
class Test {
public:
void do_something1();
...
void do_something100();
}
}
template <typename T>
class Test : public parent::Test<T> {
using parent::Test<T>::Test; // inherit constructors
}
template <>
class Test<int> : public parent::Test<int> {
using parent::Test<int>::Test;
public:
void do_something_else();
}
You can create a common base class, and make both the primary template and specialization deriving from it.
Or you can make do_something_else function template and only works with int (then don't need using specialization).
template <typename T>
class Test {
public:
void do_something1();
...
void do_something100(); // basically many functions already defined
template <typename X = T>
std::enable_if_t<std::is_same_v<X, int> && std::is_same_v<X, T>> do_something_else();
};
Or since C++20 we can use Constraints as #aschepler suggested.
template <typename T>
class Test {
public:
void do_something1();
...
void do_something100(); // basically many functions already defined
void do_something_else() requires std::is_same_v<T, int>;
};
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.
I would like to write a template function which behaves one way if the passed type is derived from any template instantiation of another class, and another way if not.
I think the code below captures what I would like to do. Unfortunately Caller prints "generic" for both double and Derived.
#include <iostream>
template <typename T>
struct Base
{
};
struct Derived
:
public Base<int>
{
};
template <typename T>
void Foo(const T&)
{
std::cout << "generic" << std::endl;
}
template <typename T>
void Foo(const Base<T>&)
{
std::cout << "derives from Base<T>" << std::endl;
}
template <typename T>
void Caller(const T& t)
{
Foo(t);
}
int main()
{
double x;
Caller(x);
Derived d;
Caller(d);
return 0;
}
(Note that Caller doesn't know which instantiation of Base that its parameter might derive from.)
It's calling the const T& overload because its a better match than const base<T>&. The reason is because calling the first requires no conversions and the second requires a derived-to-base conversion.
Here's a quick hack that shows you how it can be done (note the introduced base class):
#include <iostream>
#include <type_traits>
struct EvenMoreBase {};
template <typename T>
struct Base : EvenMoreBase
{
};
struct Derived
:
public Base<int>
{
};
template <typename T>
typename std::enable_if<!std::is_base_of<EvenMoreBase, T>::value>::type
Foo(const T&)
{
std::cout << "generic" << std::endl;
}
template <typename T>
void Foo(const Base<T>&)
{
std::cout << "derives from Base<T>" << std::endl;
}
template <typename T>
void Caller(const T& t)
{
Foo(t);
}
int main()
{
double x;
Caller(x);
Derived d;
Caller(d);
return 0;
}
If you're able to use C++11 (or <type_traits> in general), the following is also a possible solution and covers not only types T : Base<T>, i.e. instances of the CRTP, but also T : Base<U> without another base class, as requested in your example.
#include <iostream>
#include <type_traits>
template <typename T>
struct Base
{
typedef T base_value_type;
};
struct Derived : public Base<int>
{
};
template <typename T, typename = T>
struct IsDerived
{
static const bool value = false;
};
template <typename T>
struct IsDerived<T, typename std::enable_if<std::is_base_of<Base<typename T::base_value_type>, T>::value, T>::type>
{
static const bool value = true;
};
template <typename T>
void Caller(const T&)
{
std::cout << IsDerived<T>::value << std::endl;
}
int main()
{
Caller(double()); // false
Caller(Derived()); // true
return 0;
}
Note the typedef T base_value_type - which might be called whatever your like. The idea is that each type T derived from Base<U> can leverage the knowledge of the base's template parameter. It doesn't matter if T == U or not. Trying to substitute the second parameter will fail as soon as you pass in a T that has no typedef T base_value_type and thus no specialization for this particular T will be generated.
EDIT: After processing your comment, and inspired by the thread I posted, I tried to somehow extract some base parameter U when examining some time type T : Base<U>. I don't think this can be done in the way you want, i.e. you pass whatever T and you extract U. However, you can do two things.
Simple Solution: If you have control over how derived classes are implemented, instead of adding a typedef in the base class, simply add a corresponding typedef in the derived class:
template <typename BaseParamType>
class Derived : public Base<BaseParamType>
{
public:
typedef BaseParamType base_param_type;
}
or, if you don't want derived classes to be class templates as well, simply hard code the type right into the type (you already know the type of the base parameter):
class Derived : public Base<int>
{
public:
typedef int base_param_type;
}
More involved solution: What you can do, at least for an expected subset of possible Us, is the following:
template <typename DerivedType,
typename BaseParamType = DerivedType,
bool = std::is_base_of<Base<BaseParamType>, DerivedType>::value>
struct Extract
{
typedef BaseParamType type;
};
template <typename T, typename U>
struct Extract<T, U, false>;
int main()
{
Extract<DerivedCRTP>::type; // CRTP - trivial
Extract<Derived, int>::type; // type == int, Derived is derived from Base<int>
Extract<Derived, double>::type; // compile-time error, undefined template
return 0;
}
This isn't as convenient as passing some instance of a type to a deducing template function and have it magically , but you can at least test if some type T derives from Base<U> and get a compile-time error if it doesn't.
Since the base class has to be a concrete class (not a template), it is not possible to know whether it is a template or a non-template class.
In another words :
struct A1 : public B1
{};
struct A2 : public B2<int>
{};
in both of these cases both base classes are concrete types.
I'm writing an array class. This array class can contain again arrays as members. When implementing a printing function, I need specializations.
26:template <class T> class array : public vector<T>{
public:
...
string* printToString();
...
};
...
template <class T> string* array<T>::printToString(){
... // generic function
}
template <> inline string* array<double>::printToString(){
... // spezialization for double, works
}
561:template <class U> string* array<array<U>*>::printToString(){
... // does not work
}
The last definition produces
src/core/array.h:561: error: invalid use of incomplete type ‘class array<array<T> >’
src/core/array.h:26: error: declaration of ‘class array<array<T> >’
The g++ version is g++ (Ubuntu 4.4.3-4ubuntu5) 4.4.3 if that matters.
Any ideas what's the problem?
Thanks in advance,
Thomas
As an alternative to David's solution, you can unconditionally forward the call to a set of overloaded functions:
template <class T> class array;
namespace details {
template <class T> std::string array_print(array<T> const&);
std::string array_print(array<double> const&); // Regular function
template <class T> std::string array_print(array<array<T> > const&);
}
template <class T> class array : private vector<T> {
public:
...
std::string printToString() { return details::array_print(*this); }
...
};
namespace details { /* implementions after class is defined */ }
You cannot partially specialize a function, you can only fully specialize it, which is the reason why you can provide an specialization for double but not for array<U> where U is a generic type.
You can get around this limitation by using a class template, and partially specializing that, but it will be a bit cumbersome.
namespace detail {
template <typename T>
struct array_printer {
static std::string print( array<T> const & array ) {
// basic implementation
}
};
template <typename T>
struct array_printer< array<T> > {
static std::string print( array< array<T> > const & array ) {
// specialization for array<T>
}
}
}
And then implement the member function as a simple dispatch to the appropriate overload:
template <typename T>
class array : std::vector<T> { // do not publicly derive from STL containers
public:
std::string printToString() const {
return detail::array_printer<T>::print( *this );
}
}
Of course, things are a little more complex in real code, and you will have to order the code appropriatedly, and provide forward declarations of the templates and all that, but this should be enough to get you started.
Your function must be fully specialized. For example:
// Fully specialized. You cannot replace `double` with generic parameter.
template <>
string* array<array<double>*>::printToString(){
return nullptr;
}
However, your class can be partially specialized. For example:
template <class T> class array : public vector<T>{
public:
string* printToString();
};
template <class T> string* array<T>::printToString(){
return nullptr;
};
// Partial specialization.
template <class T> class array<array<T>*> : public vector<T>{
public:
string* printToString();
};
template <class T> string* array<array<T>*>::printToString(){
return nullptr;
};
-- EDIT ---
The methods from generic class will not be automatically "taken" by the class specialization, or vice-versa. You can, however use inheritance to "automate" the reuse of methods from generic class. For example...
template <class T> class array : public vector<T>{
public:
string* printToString();
void f();
};
// (1a)
template <class T> string* array<T>::printToString(){
return nullptr;
};
// (2)
template <class T> void array<T>::f(){
};
template <class T> class array<array<T>*> : public array<T> {
public:
string* printToString();
};
// (1b)
template <class T> string* array<array<T>*>::printToString(){
return nullptr;
};
void Test() {
array<double> a1;
a1.printToString(); // Calls (1a).
a1.f(); // Calls (2).
array<array<char>*> a2;
a2.printToString(); // Calls (1b).
a2.f(); // Calls (2).
}
...which may or may not be what you need (some "manual" repetition might be necessary).