So I have a tremendous number of template specializations of this template:
template <typename T> // Same
struct foo { // Same
using type_name = T; // Same
foo(const int base) : _base(base) {} // May take other parameters
void func(const T& param) {} // This function signature will be the same but body will differ
int _base; // Same but may have more members
}; // Same
So an example specialization would be:
template<>
struct foo<float> {
using type_name = T;
foo(const int base, const int child) : _base(base), _child(child) {}
void func(const T& param) { cout << param * _child << endl; }
int _base;
int _child;
};
Obviously this is a toy example and the body of _func will be more involved. But I think this expresses the idea. I can obviously make a macro to help with the boilerplate and put the implementation of the specialized version of the function in an implementation file.
But I was hoping that C++ provided me a way to do this without macros. Is there another way for me avoid writing the boilerplate over and over?
you can have multiple specialization for the function but not for the whole class
like this
#include <iostream>
#include <string>
template<typename T>
struct foo {
//common generic code
using type_name = T;
foo(const int base, const int child) : _base(base), _child(child) {}
void func(const T& param);
int _base;
int _child;
};
template<>
void foo<float>::func(const type_name&) {
//implementation
std::cout << "float" << std::endl;
}
template<>
void foo<int>::func(const type_name&) {
//implementation
std::cout << "int" << std::endl;
}
int main() {
foo<int> tint(0, 0);
foo<float> fint(0, 0);
tint.func(0);
fint.func(0);
}
You can use some light inheritance of data structs to help you separate the differences in member layout and constructor definitions from the main template.
//Define an internal aggregate type you can specialize for your various template parameters
template <typename T>
struct foo_data {
foo(const int base) : _base(base) {}
int _base;
};
//Then derive privately from the data struct (or publicly if you really desire)
template <typename T>
struct foo : private foo_data<T> {
using type_name = T;
using foo_data<T>::foo_data<T>; //Make the base class constructors visible
void func(const T& param); //Use member specialization as suggested by the other answer
};
I will leave it to you to decide if it is better this way or not, but the upshot is that all the common parts are completely separated from all the uncommon parts.
In a comment under another answer I erroneously described this as CRTP. It isn't and it doesn't have any of the drawbacks as CRTP.
If you really need to preserve standard layout, then you can simulate inheritance manually with explicit delegation and perfect forwarding.
template <typename T>
struct foo {
using type_name = T;
template <typename... Args>
foo(Args&&... args) : base_data_(std::forward<Args>(args)...) {}
void func(const T& param); //Use member specialization as suggested by the other answer
foo_data<T> base_data_;
};
One drawback is I don't think the delegating constructor will SFINAE properly as written, and it also eats noexcept specifiers and explicit. Fixing those issues(if required) is left as an exercise to the reader.
There is no nice way to avoid some redundancy in notation when implementing specializations of templated types. There are some techniques to avoid duplication of actual code, such as
Using a traits template to provide type-specific things
template<typename T>
struct foo_traits { ... }; // provide many specialisations
template<typename T> // no specialisations
struct foo
{
using traits = foo_traits<T>;
template<typename...Aars>
explicit foo(Args&&...args)
: data(std::forward<Args>(args)...) {}
int do_something_specific(T x)
{ return traits::do_something(data,x); }
private:
typename traits::data data;
};
a very similar approach is to use a specialized base class:
template<typename T>
struct foo_base { ... }; // provide many specialisations
template<typename T> // no specialisations
struct foo : foo_base<T>
{
using base = foo_base<T>;
template<typename...Aars>
explicit foo(int m, Args&&...args)
: base(std::forward<Args>(args)...)
, more_data(m) {}
int do_something_specific(T x)
{ return base::do_something(x,more_data); }
private:
int more_data;
};
The constructor of foo is a variadic template in order to allow the base class's constructor to take any number and type of arguments.
Of you can use a common base class and specialize the derived classes. This can be done with the Curiously recurring template pattern (CRTP)
template<typename Derived>
struct foo_base // no specializations
{
using type = typename Derived::type;
int do_something(type x)
{
auto result = static_cast<Derived*>(this)->specific_method(x);
return do_some_common_stuff(result);
}
protected:
foo_base(type x) : data(x) {}
type data;
private:
int do_some_common_stuff(type x)
{ /* ... */ }
};
template<typename T> // some specialisations
struct foo : foo_base<foo<T>>
{
using base = foo_base<foo>;
using type = T;
using common_type = typename base::common_type;
using base::do_something;
explicit foo(type x, type y)
: base(x), extra_data(y) {}
protected:
type specific_method(type x)
{ /* ... */ }
private:
type extra_data;
};
Note that foo_base is already a template (unlike the situation with ordinary polymorphism), so you can do a lot of specific stuff there already. Only things that are done differently (not merely with different types) need specializations of foo.
Finally, you can combine these approaches, for example traits classes with CRTP.
All these methods implement some type of static or compile-time polymorphism, rather than real or dynamic polymorphism: there are no virtual functions and hence no virtual table and no overhead for table look-up. It is all resolved at compile time.
This is usually done through inheritance - you put the immutable part into base class, and specialize the children.
I do not think you need an example for that, but let me know if you do.
Related
Let's say I have the following class:
template <typename T>
class SomeClass : Parent<T>
{
public:
// I have a function such as this one:
T DoSomething(const T &t)
{
return t.DoSomething(some_data);
}
// But `T` might be a pointer, so sometimes I will need something like the following
// instead (which obviously doesn't work as given):
T DoSomething(const T &t)
{
return new T(t->DoSomething(some_data));
}
private:
XYZ some_data;
};
I got stuck in a giant mess of template errors trying to implement this in any semi-nice way possible using template specialization.
In the end I came up with this very ugly solution:
template <typename T>
class SomeClass : Parent<T>
{
public:
T DoSomething(const T &x)
{
return Specializer<T>::Do(this, x);
}
private:
template <typename V>
struct Specializer {
static V Do(SomeClass *me, const V &x)
{
return x.DoSomething(me->some_data);
}
};
template <typename V>
struct Specializer<V*> {
static V* Do(SomeClass *me, const V *&x)
{
return new V(x->DoSomething(me->some_data));
}
};
XYZ some_data;
};
Is there a better way to do this that doesn't involve stuffing this function into a dummy class/struct and passing around my this pointer?
PS: In reality, this has nothing to do with pointers, but rather with different types of containers. Pointers were just an easy example to use here.
You can avoid writing any specializations, and use a type trait like std::is_pointer along with if constexpr to decide what code to execute depending on the whether the type is a pointer type or not:
auto DoSomething(const T &t)
{
if constexpr (std::is_pointer_v<T>)
return new T(t->DoSomething(some_data));
else
return t.DoSomething(some_data);
}
If you don't want to check for whether T is a pointer, but want to check something else, you can still use this pattern by dropping in a suitable replacement for is_pointer.
If you have access to c++20, you can clean up the need for any SFINAE, specializations, or if constexpr by using concepts and constraints instead. This just allows you to define the same function N times with different criteria for its insantiation, which is much more readable IMO.
This is almost the same as the SFINAE approach, but without the need for the awful syntax (no std::declval, decltype, etc). It also doesn't require all implementations to exist in one function definition like the if constexpr approach; all you need is separate function definitions with different requires clauses:
#include <concepts>
...
template <typename T>
class SomeClass : Parent<T>
{
public:
// Work for everything that's not specialized
void DoSomething(const T &t)
{
std::cout << "Basic overload" << std::endl;
}
// Only work for pointers
void DoSomething(const T& t) requires(std::is_pointer_v<T>)
{
std::cout << "Pointer overload" << std::endl;
}
// Only work if T is convertible to SomeType
void DoSomething(const T& t) requires(std::convertible_to<T, SomeType>)
{
std::cout << "Convertible to SomeType overload" << std::endl;
}
private:
XYZ some_data;
};
Live Example
In this approach there are 3 different entries:
The basic fallback for all templates
An implementation that works for any pointer type, and
An implementation that works for any T type that may be convertible to SomeType
What about using SFINAE?
For example
#include <utility>
#include <iostream>
template <typename>
struct Parent
{ };
using XYZ = int;
template <typename T>
class SomeClass : Parent<T>
{
public:
template <typename U = T>
auto DoSomething (T const & t)
-> decltype( std::declval<U>().DoSomething(std::declval<XYZ>()) )
{ std::cout << "ref\n"; return t.DoSomething(some_data); }
template <typename U = T>
auto DoSomething (T const & t)
-> std::remove_reference_t<
decltype( std::declval<U>()->DoSomething(std::declval<XYZ>()),
std::declval<T>() )>
{
using V = std::remove_reference_t<decltype(*t)>;
std::cout << "pnt\n"; return new V(t->DoSomething(some_data));
}
private:
XYZ some_data;
};
struct foo
{
foo (foo*) {}
foo () {}
foo DoSomething (int) const { return {}; }
} ;
int main()
{
SomeClass<foo> sc1;
SomeClass<foo*> sc2;
foo f;
sc1.DoSomething(f);
sc2.DoSomething(&f);
}
I mean: what about enabling the first version if, and only if, T is a type that supports a DoSomething(XYZ) method and enabling the second version if, and only if, T is a pointer of a type that supports a DoSomething(XYZ) method?
I'm biting of my nails on the syntax required to partially specialize a member function for multiple types. Here is what I have:
#include <cstdint>
#include <string>
class Property
{
public:
virtual int read(uint8_t *) = 0;
};
template<typename T>
class PropertyValue
{
T value_;
public:
int read(uint8_t *);
};
// specialized for std::string
template<>
int PropertyValue<std::string>::read(uint8_t *buf) { /* put string-value to buf */}
Now I would want to specialize the read-function for different enum-types. I tried a combination of enable_if and is_same which looks promissing, then putting it inside the template-declaration (compiler told me there are now 2 template arguments whereas 1 was expected).
Putting it inside the class-definition was not working either. Outside ... well, here's what I currently have.
// specialize for some enums
template<typename T>
typename std::enable_if<std::is_same<T, enum Enum1>::value ||
std::is_same<T, enum Enum2>::value, int>::type
PropertyValue<T>::read(uint8_t *buf)
{
return encode_enum(buf, value_);
}
Where is my thinking wrong?
EDIT: Writing it like this compiles and works:
template<>
int PropertyValue<Enum 1>::read(uint8_t *buf)
{
return encode_enum(buf, value_);
}
template<>
int PropertyValue<Enum 2>::read(uint8_t *buf)
{
return encode_enum(buf, value_);
}
PropertyValue::value itself is not a template. It's not a template class, it's not a template function. It's a member of a template class, which is not the same thing as being a template itself.
You have to specialize the entire class.
template<>
class PropertyValue<std::string>
{
std::string value_;
public:
int read(uint8_t *)
{
// Your specialization goes here.
}
};
Even if read() itself was a template, you must still specialize its class, before you can specialize a template class's template member.
Of course, if your template class has many other members and methods, every one of them have to be specialized here, leading to plenty of code getting duplicated. At that point, you will be faced with several options for refactoring out that duplicated code. The best approach for that depends on the particular details.
But that's how it's done...
EDIT: one common approach is to use a helper template class:
template<typename T> class PropertyValue; // Forward declaration
template<typename T> class do_read {
public:
static int do_it( PropertyValue<T> &me, uint8_t *p )
{
// your default implementation
}
};
template<> class do_read<std::string> {
public:
static int do_it( PropertyValue<std::string> &me, uint8_t *p )
{
// your specialization
}
};
template<typename T>
class PropertyValue
{
T value_;
public:
int read(uint8_t *p)
{
return do_read<T>::do_it(*this, p);
}
};
Is it possible to create a class template with a member function definition only if the object created is of a specific type?
I've created a template class I will use for storing either int or doubles, but for doubles I would like to be able to set precision too (objects created with myclass < double> should have this functionality, but for myclass< int> there is no need for that to be present at all).
I know I can use a base class template, and create new classes "myInt", "myDouble" using that and implement the functionality only in the myDouble class, but I think it would be cleaner to define the functionality (both the function and a member variable) for doubles in the class template, if that's possible and preferable?
Let's add an example to show what I want to do:
#include <iostream>
#include <iomanip>
class commonBase{
public:
void setState(int state);
virtual void print() = 0;
private:
int _my_state;
};
template <typename T>
class generalObject : public commonBase {
public:
void value(T value);
void print(){ std::cout << "My value: " << _my_value << std::endl; }
private:
T _my_value;
};
template <typename T>
void generalObject<T>::value(T value){
_my_value = value;
}
// Is there any way do specialize only only whats different from the generalObject template?
// Here I thought I could specialize the case where a generalObject is created of <double>, but
// when I do, nothing is derived from generalObject (or at least not visible as far as I can tell)
template<>
class generalObject<double>{
public:
void setPrecision(int precision){ _my_precision = precision; }
// here I would like a special implementation of print(), which overrides the print() in generalObject
// and instead also prints according to the precision set when the object is of <double> type.
// Row below an example which doesn't work (compiler error, _my_value undefined)
void print(){ std::cout << "My value: " << std::setprecision(_my_precision) << _my_value << std::endl; }
private:
int _my_precision;
};
int main(int argc, char* argv[]){
generalObject<int> o1;
o1.value(1);
o1.print();
o1.setState(1); //inherited from the commonBase
generalObject<double> o2;
o2.setPrecision(2);
o2.value(2); //here value isn't available (compile error)
o2.print();
o2.setState(123); //also isn't available (compile error)
}
Sure.
template <typename T> class Poly;
void set_precision(Poly<double>* self, int a) {};
If you really want dot notation you can then add:
template <typename T> class Poly {
public: void set_precision(int a){::set_precision(this,a);}
...
However I think you should think about what you're trying to accomplish. If MyInt and MyDouble have different fields and different methods and different implementations, they should probably be different classes.
This can be solved using template specialization.
We first define a common template...
template< typename T >
struct myclass
{
// common stuff
};
... and specialize that for double:
template<>
struct myclass<double>
{
int precision = 10;
void setprecision( int p ){ precision = p; }
};
Now the setprecision() method can only be called for myclass<double>. The compiler will complain if we try to call it for anything else, like myclass<int>.
int main()
{
myclass<double> d;
d.setprecision( 42 ); // compiles
myclass<int> i;
i.setprecision( 42 ); // fails to compile, as expected
}
Demo.
The basic way to have a member function of a class template exist only for some template parameters is to create a specialization of the class template for those template parameters.
template<typename T>class X{
// general definition
};
template<>class X<double>{
// double-specific definition
};
The downside of this is that the specialization will need to duplicate anything that is common. One way to address this is to move the common things out to a base class template:
template<typename T>class Xcommon{
// common stuff
};
template<typename T>class X: public Xcommon<T>{
// general definition
};
template<>class X<double>: public Xcommon<double>{
// double-specific definition
};
Alternatively, you can do it the other way: put the common stuff in the derived class, and the extras in the base, and specialize the base:
template<typename T>class Xextras{
// empty by default
};
template<typename T>class X: public Xextras<T>{
// common definition
};
template<>class Xextras<double>{
// double-specific definition
};
Either way can work; which is better depends on the details.
Both these methods work for data members and member functions.
Alternatively, you can use enable_if to mean that member functions are not selected by overload resolution if the template parameter doesn't meet a required condition. This requires that the member function is itself a template.
template<typename T>class X{
template<typename U=T> // make it a template,
std::enable_if<std::is_same_v<U,double>> double_specific_function(){
// do stuff
}
};
I wouldn't recommend this option unless there is no other choice.
If the question is about a member function, then here is one of the ways to do it without class template specialization:
#include <iostream>
#include <type_traits>
template <typename T>
struct Type {
template <typename U = T,
typename = typename std::enable_if<std::is_same<U, double>::value>::type>
void only_for_double() {
std::cout << "a doubling" << std::endl;
}
};
int main() {
Type<int> n;
Type<double> d;
// n.only_for_double(); // does not compile.
d.only_for_double();
}
Example on ideone.com
If you require a data-member presence based on the template parameter, you will have to do some kind of specialization, in which case it is, probably, simpler to put the function into corresponding specialization.
EDIT: After OP made his question more specific
Here is one way to do it without extra class and getting rid of virtual functions. Hope it helps.
#include <iostream>
#include <iomanip>
template <typename T, typename Derived = void>
class commonBase {
public:
void setState(int state) {
_my_state = state;
}
void value(T value) {
_my_value = value;
}
template <typename U = Derived,
typename std::enable_if<std::is_same<U, void>::value,
void * >::type = nullptr>
void print() const {
std::cout << "My value: " << _my_value << std::endl;
}
template <typename U = Derived,
typename std::enable_if<!std::is_same<U, void>::value,
void * >::type = nullptr>
void print() const {
static_cast<Derived const *>(this)->_print();
}
protected:
T _my_value;
int _my_state;
};
template <typename T>
class generalObject : public commonBase<T> {
};
template<>
class generalObject<double> : public commonBase<double, generalObject<double>> {
private:
friend commonBase<double, generalObject<double>>;
void _print() const {
std::cout << "My value: " << std::setprecision(_my_precision) <<
_my_value << std::endl;
}
public:
void setPrecision(int precision){ _my_precision = precision; }
private:
int _my_precision;
};
int main(){
generalObject<int> o1;
o1.value(1);
o1.print();
o1.setState(1);
generalObject<double> o2;
o2.setPrecision(2);
o2.value(1.234);
o2.print();
o2.setState(123);
}
Same code on ideone.com
I know partial template specialization isn't supported for functions and class methods, so my question is: What are common solutions or patterns to resolve this? Below Derived derives from Base, and both of these classes have virtual methods greet() and speak(). Foo's holds a std::array<unique_ptr<T>, N> and is used in do_something(). Foo has two template parameters: T (the class type) and N (number of elements of the std::array) If N = 2, there exists a highly optimized version of do_something(). Now assume that Foo's T parameter isn't always the base class Base. Ideally, I would like to write the following code, but it's illegal:
//ILLEGAL
template<typename T>
void Foo<T,2>::do_something()
{
arr_[0]->greet();
}
Below is the full code and my current (ugly) solution. I have to specialize do_something() twice, once for Base and once for Derived. This gets ugly if there exists multiple methods like do_something() that can be optimized on the special N=2 case, and if there exists many subclasses of Base.
#include <iostream>
#include <memory>
class Base
{
public:
virtual void speak()
{
std::cout << "base is speaking" << std::endl;
}
virtual void greet()
{
std::cout << "base is greeting" << std::endl;
}
};
class Derived : public Base
{
public:
void speak()
{
std::cout << "derived is speaking" << std::endl;
}
void greet()
{
std::cout << "derived is greeting" << std::endl;
}
};
template<typename T, int N>
class Foo
{
public:
Foo(std::array<std::unique_ptr<T>, N>&& arr) :
arr_(std::move(arr))
{
}
void do_something();
std::array<std::unique_ptr<T>, N> arr_;
};
template<typename T, int N>
void Foo<T,N>::do_something()
{
arr_[0]->speak();
}
//Want to avoid "copy-and_paste" of do_something() below
template<>
void Foo<Base,2>::do_something()
{
arr_[0]->greet();
}
template<>
void Foo<Derived,2>::do_something()
{
arr_[0]->greet();
}
int main()
{
constexpr int N = 2;
std::array<std::unique_ptr<Derived>, N> arr =
{
std::unique_ptr<Derived>(new Derived),
std::unique_ptr<Derived>(new Derived)
};
Foo<Derived, N> foo(std::move(arr));
foo.do_something();
return 0;
}
The trick is to forward implementation to an helper template class, and partial specialize that class and/or use tag dispatching:
namespace {
template<typename T, int N, bool isBase = std::is_base_of<Base, T>::value>
struct helper {
// general case:
void operator () (std::array<std::unique_ptr<T>, N>& arr_) const
{
arr_[0]->speak();
}
};
template<typename T>
struct helper<T, 2, true>
{
void operator () (std::array<std::unique_ptr<T>, 2>& arr_) const
{
arr_[0]->greet();
}
};
// You may add other specialization if required.
}
template<typename T, int N>
void Foo<T,N>::do_something()
{
helper<T, N>()(arr_);
}
There are different alternatives, depending on how other constrains in the problem one might be more appropriate than another.
The first one is to forward the request to a static function in a template class, which allows for partial specializations:
template <int N>
struct Helper {
template <typename T>
static void talk(T& t) { // Should be T const &, but that requires const members
t.speak();
}
};
template <>
struct Helper<2> {
template <typename T>
static void talk(T& t) {
t.greet();
}
}
;
Then the implementation of do_something would be:
template <typename T, int N>
void Foo<T,N>::do_something() {
Helper<N>::talk(*arr_[0]);
}
Alternatively, you can use tag dispatch to select one of multiple overloads:
template <int N> struct tag {};
template <typename T, int N>
template <int M>
void Foo<T,N>::do_something_impl(tag<M>) {
arr_[0]->speak();
}
template <typename T, int N>
void Foo<T,N>::do_something_impl(tag<2>) {
arr_[0]->greet();
}
template <typename T, int N>
void Foo<T,N>::do_something() {
do_something_impl(tag<N>());
}
Where I have created a tag-type that can be specialized for any possible N. You could also use existing tools in C++11.
Finally, if you need to do something like this for different functions, you can use inheritance, and push some of the functionality to a base that resolves the differences. This can be done by either pushing common code to a base, differences to an intermediate level and using a lower level front type that just inherits from the rest (base contains generic code, derived types specialize). Or alternatively with CRTP (base(s) contain differences, derived type generic code and pulls specific implementations from the bases.
I'm trying to create a class which will contain a map of type_index keys mapped to pointers of each type passed as a template argument. This would allow me to specify a series of types my class will rely on in it's declaration.
I've done a bit of research but can only seem to find ways to unpack arguments, rather than types. I'm new to this subject, and would appreciate any clarification on terminology, or references to relevant text.
template <typename T>
T* SomeFakeFactoryGetter() { return new T(); }
template <class... Injected>
class UtilityProvider
{
public:
template <class U>
U* GetUtility()
{
std::type_index idx = std::type_index(typeid(U));
assert(_injectedClasses.find(idx) != _injectedClasses.end());
return reinterpret_cast<U*>(_injectedClasses[idx]);
}
// **
// How would I *unpack* all types for use as indices into my map?
// ( I realise this function is not what I want.)
template <Injected... C>
void Unpack()
{
_injectedClasses[std::type_index(typeid(C))] = SomeFakeFactoryGetter<C>();
}
private:
typedef std::unordered_map<std::type_index, void*> InjectedMap;
InjectedMap _injectedClasses;
};
class Bar{ public: void A() { printf("Hello bar"); } };
class Baz{ public: void B() { printf("Hello baz"); } };
class Nope {};
class Foo : public UtilityProvider<Bar, Baz>
{
public:
Foo()
{
GetUtility<Bar>()->A();
GetUtility<Nope>(); // Fail. User must specify which utilities this class will use.
}
};
What I've done in this situation is to create a dummy function to expand these expressions into, but it looks quite hideous:
template <int ... Dummies>
void dummy(int&& ...){}
template <class ... C>
void Unpack()
{
dummy(((_injectedClasses[std::type_index(typeid(C))] =
SomeFakeFactoryGetter<C>()), 0)...);
}
Note that in your case I think you'll be better off with using insert with an initializer_list:
template <class ... C>
void Unpack()
{
_injectedClasses.insert({std::make_pair(std::type_index(typeid(C)),
SomeFakeFactoryGetter<C>())...});
}
I couldn't find a direct mention of this but I believe there is an important difference between the two methods, in case you didn't already know. insert will not override existing key-value pairs, whereas operator[] will. This can affect which method you should use if if this is important to you.
An alternative approach:
template <typename ... C> struct Unpacker;
template <typename Tail, typename ... Queue>
struct Unpacker<Tail, Queue...>
{
void operator () (InjectedMap& injectedClasses) const
{
_injectedClasses[std::type_index(typeid(Tail))] = SomeFakeFactoryGetter<Tail>();
Unpacker<Queue...>()(injectedClasses);
}
};
template <>
struct Unpacker<>
{
void operator () (InjectedMap& injectedClasses) const {}
};