I have a class that can either be constructed by arguments of "ordinary" types, int, string, etc., or that can be constructed by a couple of different 'special' types invented by a coworker.
The 'special' types have the same signature, but aren't in a parent-child relationship.
So the code I have now looks something like:
class my_nifty_class {
public:
// "ordinary" constructor
template <class T> my_nifty_class(T) {some generic code}
// "special" constructors
my_nifty_class(my_first_clever_class) {
some clever code
}
my_nifty_class(my_second_clever_class) {
the identical clever code
}
In order to avoid duplicating some clever code (and opening myself up to the risk of not always duplicating it right), I would like to replace this with
class my_nifty_class {
public:
// "ordinary" constructor
template <class T> my_nifty_class(T) {some generic code}
// "special" constructors
template <class clever_class> my_nifty_class(clever_class) {
/**** I need template magic somewhere around here ****/
some clever code
}
But -- I don't know the template magic to put in there, or if there is any such magic to be had. I know I could do it if I were declaring classes -- but I'm declaring functions, so I'm kinda stuck.
You want std::enable_if, and you want some compile-time property of your special classes that other classes don't have.
template <class T, class S = std::enable_if_t<!is_my_special_v<T>>>
my_nifty_class(T) {some generic code}
template <class T, class S = std::enable_if_t<is_my_special_v<T>>, bool = true>
my_nifty_class(T) {some special code}
(The dummy template parameter is needed to make the two templates distinct)
Another method is to have just one constructor and use the special selector inside.
template <class T>
my_nifty_class(T) {
if constexpr(is_my_special_v<T>)
some special code
else
some generic code
}
How do you write is_my_special_v? It is just a template with the value of false, with specialisations for your special types with the value of true.
template<class> constexpr bool is_my_special_v = false;
template<> constexpr bool is_my_special_v<MySpecialType1> = true:
// ...
If all your special classes have some member name that is unlikely to occur in non-special classes, you can use that in order to write just one specialisation of is_my_special_v total instead of one per special class. Search for "c++ member detection", lots of material out there.
Finally, if this is the only place where your special types are indeed special, you can skip
is_my_special_v altogether and just check directly.
template <class T>
my_nifty_class(T) {
if constexpr(std::is_same_v<T, MySpecialType1> ||
std::is_same_v<T, MySpecialType2> ...)
some special code
else
some generic code
}
Here is my go at the answer. You will just share a generic constructor for all types. And handle the logic within the constructor using std::is_pod which was introduced in c++11 I believe.
Essentially POD (plain old data) types such as; int, float, double, etc. will be handled by one templated function, and any complex/non-trivial data types will be handled by your other templated function.
class my_nifty_class {
public:
template<class T> handle_pod_type(T value)
{ /* Code to handle POD data types */ }
template<class SpecialType> handle_special_type(SpecialType value)
{ /* Code to handle complex data types */ }
template <class T> my_nifty_class(T value) {
if( std::is_pod<T>::value ) {
handle_pod_type(value);
}
else {
handle_special_type(value);
}
}
}
Also take note of what is_pod is doing and what classifies a POD type in C++11.
I suggest that you can use "tag structures" and class template specializations to solve your problem:
struct TypeA {};
struct TypeB {};
struct TypeC {};
class Class {
public:
template<class T> Class(T val) : Class(typename SelectTag<T>::Type{}, val) {}
private:
struct GenericTag {};
struct BOrCTag {};
template<class T> struct SelectTag { using Type = GenericTag; };
template<class T> Class(GenericTag, T val) { /* do smth */ }
template<class T> Class(BOrCTag, T val) { /* do smth else */ }
};
template<> struct Class::SelectTag<TypeB> { using Type = BOrCTag; };
template<> struct Class::SelectTag<TypeC> { using Type = BOrCTag; };
Related
I'm using a "traits" pattern where I have a base case expressed as a class template
template <class>
struct DoCache {
constexpr static bool value = false;
};
and I expect users to specialize for their types:
template <>
struct DoCache<MyType> {
constexpr static bool value = true;
static void write2Cache(MyType const&) { /* implementation */ }
static optional<MyType> readFromCache(string name) { /* implementation */ }
};
The typical use is to retrieve and use this as:
// Define a variable template
template <class T>
constexpr bool do_cache_v = DoCache<T>::value;
// Use the above trait in compile time branching:
if constexpr (do_cache_v<T>)
{
write2Cache(arg);
}
There's two problems I have with this code:
A user is only indirectly enforced to provide a "value" member when specializing, let alone making it the proper value (i.e. true). By indirectly I mean they'll get a bunch of compilation errors that one can only solve if they know the answer beforehand.
There's no way of "requiring" them to create the two needed methods, namely write2Cache and readFromCache, let alone having (const) correct types.
In some code-bases I've seen the considerations above being tackled by defining a generator macro like:
#define CACHABLE(Type, Writer, Reader) ...
Is there a better way to it?
Can concepts be used to restrict the way a specialization looks?
Is there a C++17 compatible way?
an answer to any of the above is appreciated
C++17: Curiously recurring template pattern
It seems like a suitable use case for CRTP:
template<typename T>
struct DoCache {
void write2Cache() {
static_cast<T*>(this)->write2Cache();
}
// ...
};
template<typename T>
void write2Cache(DoCache<T>& t) {
t.write2Cache();
}
struct MyType : DoCache<MyType>
{
void write2Cache() { /* ... */ }
};
int main() {
MyType mt{};
write2Cache(mt);
}
Instead of requiring clients to specialize a library type over their own types, you require them to implementes their own types in-terms-of (static polymorphism) the contract/facade of the library type.
C++20: Concepts
With concepts you can skip polymorphism entirely:
template<typename T>
concept DoCachable = requires(T t) {
t.write2Cache();
};
template<DoCachable T>
void write2Cache(T& t) {
t.write2Cache();
}
struct MyType {
void write2Cache() { /* ... */ }
};
struct MyBadType {};
int main() {
MyType mt{};
write2Cache(mt);
MyBadType mbt{};
write2Cache(mbt); // error: ...
// because 'MyBadType' does not satisfy 'DoCachable'
// because 't.write2Cache()' would be invalid: no member named 'write2Cache' in 'MyBadType'
}
However again placing requirements on the definition site of client type (as opposed to specialization which can be done after the fact).
Trait-based conditional dispatch to write2Cache()?
But how is the trait do_cache_v exposed this way?
C++17 approach
Since the CRTP-based approach offers an "is-a"-relationsship via inheritance, you could simply implement a trait for "is-a DoCache<T>":
#include <type_traits>
template<typename>
struct is_do_cacheable : std::false_type {};
template<typename T>
struct is_do_cacheable<DoCache<T>> : std::true_type {};
template<typename T>
constexpr bool is_do_cacheable_v{is_do_cacheable<T>::value};
// ... elsewhere
if constexpr(is_do_cacheable_v<T>) {
write2Cache(t);
}
C++20 approach
With concepts, the concept itself can be used as a trait:
if constexpr(DoCachable<T>) {
write2Cache(t);
}
You can use a concept to sanity check specializations. Here you only need to provide the correct, by name & type, methods hence the ::value member in DoCache can be deprecated:
template <class T>
concept Cacheable = requires (T const& obj) {
{ DoCache<T>::write2Cache(obj) }
-> std::same_as<void>;
{ DoCache<T>::readFromCache(std::string{}) }
-> std::same_as<std::optional<T>>;
};
Usage is similar to the trait:
if constexpr (Cacheable<MyStruct>)
and enforces proper specialization of DoCache.
Demo
The method shown above implies that a user is allowed to specialize DoCache in an improper way, resulting in a "non cacheable" type. To prevent this from happening you can:
Use defensive programming by placing a static_assert(Cacheable<MyStruct>) after the specialization.
Leverage a constexpr static value member again and enforce an all or nothing policy in specializations, i.e. either a specialization is not provided for the type, or the provided specialization contains all members as specified in the concept. This implies you'll use a trait whose template parameter is the concept.
This is not a major code breaking issue, I'm just wondering if I'm missing some neat trick.
If I am writing a templated class, I may start like this:
// some_header.h
template <typename TypeParameter, size_t max_array_size>
class TemplatedClass
{
std::array<TypeParameter, max_array_size> MyTemplatedArray;
public:
TypeParameter do_something()
{
/* do something with TypeParameter and max_array_sizein here */
}
}
This is fine, but when I have less trivial templated examples, I tend to separate out the function definitions from the declarations, like so:
// some_header.h
template <typename TypeParameter, size_t max_array_size>
class TemplatedClass
{
std::array<TypeParameter, max_array_size> MyTemplatedArray;
public:
TypeParameter do_something();
/*
Many more function declarations
*/
}
template <typename TypeParameter, size_t max_array_size>
TemplatedClass<TypeParameter, max_array_size>::do_something()
{
/* do something with TypeParameter and max_array_sizein here */
}
/*
Many more function definitions, all with:
template <typename TypeParameter, size_t max_array_size>
TemplatedClass<TypeParameter, max_array_size>
at the start
*/
The aim of this would be to have a classic skeleton class definition that can easily be read by others at a glance. I don't mind doing this, but the annoying thing is when I want to modify the template parameters. What is one change in the first example, ends up being 1 + 2 * n changes in the second example!
So what I am wanting to know is: Is there a way to make the second example's template parameters more maintainable? Maybe something similar to a typedef/using or maybe some keyword I haven't heard of?
First a non-answer:
Suppose, /*do something*/ depends on the template parameters. In that case, having to fix the signature is the smaller issue. You need to fix the implementation.
The other case is that /*do something*/ does not depend on the template parameters. Then you can move the methods to a non template base class.
A more serious attempt to answer the question:
What if TemplatedClass would have only a single template parameter instead of many? Instead of using a bunch of template parameters for TemplatedClass you can use a single tag and definition of the actual parameters can be defered to traits:
#include <array>
template <typename Tag> struct value_type_impl;
template <typename Tag> using value_type = typename value_type_impl<Tag>::type;
template <typename Tag> constexpr int array_size = 123;
template <typename Tag>
class TemplatedClass {
std::array<value_type<Tag>, array_size<Tag> > MyTemplatedArray;
public:
value_type<Tag> do_something();
};
template <typename Tag>
value_type<Tag> TemplatedClass<Tag>::do_something() {
return {};
}
// the tag
struct foo_tag{};
// specializations for foo_tag:
template <> struct value_type_impl<foo_tag> { using type = int; };
template <> constexpr int array_size<foo_tag> = 123;
int main() {
TemplatedClass<foo_tag> tc;
}
Now the burdon is on the user of the template to define one tag and then specialize the required traits for that tag. Though, the method definition has only a single template parameter that does not need to change when more "parameters" (traits) are added or removed. Of course you still need to fix the implementation.
If you were looking merely for some syntactic sugar, I am not aware of something that would help without changing the template itself.
I am trying to write a class template that uses a parameter-pack and implements a member function for each type contained in the parameter-pack.
This is what I have so far:
template <typename...T>
class Myclass {
public:
void doSomething((Some_Operator_to_divorce?) T) {
/*
* Do Something
*/
std::cout << "I did something" << std::endl;
}
};
My goal is to have a class template that can be used in the following way:
Myclass<std::string, int, double> M;
M.doSomething("I am a String");
M.doSomething(1234);
M.doSomething(0.1234);
Where the class template mechanism will create an implementation for a doSomething(std::string x), a doSomething(int x) and a doSomething(double x) member function but not a doSomething(std::string x, int i, double f) member function.
I found a lot of examples in the web on the usability of parameter-packs, but I could not figure out if it can be used for my purpose, or if I totally misunderstood for what a parameter-pack can be used.
I thought that I need to unpack the parameter-pack but, after reading a lot of examples about unpacking parameter packs, I believe that this is not the right choice and it has a complete different meaning.
So, therefore, I am looking for a operation to "divorce" a parameter-pack.
There is no "operator" specifically that supports this, but what you're requesting can be done in a few different ways, depending on your requirements.
The only way to "extract" T types from a parameter pack of a class template with the purpose of implementing an overload-set of functions is to implement it using recursive inheritance, where each instance extracts one "T" type and implements the function, passing the rest on to the next implementation.
Something like:
// Extract first 'T', pass on 'Rest' to next type
template <typename T, typename...Rest>
class MyClassImpl : public MyClassImpl<Rest...>
{
public:
void doSomething(const T&) { ... }
using MyClassImpl<Rest...>::doSomething;
};
template <typename T>
class MyClassImpl<T> // end-case, no more 'Rest'
{
public:
void doSomething(const T&) { ... }
};
template <typename...Types>
class MyClass : public MyClassImpl<Types...>
{
public:
using MyClassImpl<Types...>::doSomething;
...
};
This will instantiate sizeof...(Types) class templates, where each one defines an overload for each T type.
This ensures that you get overload semantics -- such that passing an int can call a long overload, or will be ambiguous if there are two competing conversions.
However, if this is not necessary, then it'd be easier to enable the function with SFINAE using enable_if and a condition.
For exact comparisons, you could create an is_one_of trait that only ensures this exists if T is exactly one of the types. In C++17, this could be done with std::disjunction and std::is_same:
#include <type_traits>
// A trait to check that T is one of 'Types...'
template <typename T, typename...Types>
struct is_one_of : std::disjunction<std::is_same<T,Types>...>{};
Alternatively, you may want this to only work if it may work with convertible types -- which you might do something like:
template <typename T, typename...Types>
struct is_convertible_to_one_of : std::disjunction<std::is_convertible<T,Types>...>{};
The difference between the two is that if you passed a string literal to a MyClass<std::string>, it will work with the second option since it's convertible, but not the first option since it's exact. The deduced T type from the template will also be different, with the former being exactly one of Types..., and the latter being convertible (again, T may be const char*, but Types... may only contain std::string)
To work this together into your MyClass template, you just need to enable the condition with SFINAE using enable_if:
template <typename...Types>
class MyClass
{
public:
// only instantiates if 'T' is exactly one of 'Types...'
template <typename T, typename = std::enable_if_t<is_one_of<T, Types...>::value>>
void doSomething(const T&) { ... }
// or
// only instantiate if T is convertible to one of 'Types...'
template <typename T, typename = std::enable_if_t<is_convertible_to_one_of<T, Types...>::value>>
void doSomething(const T&) { ... }
};
Which solution works for you depends entirely on your requirements (overload semantics, exact calling convension, or conversion calling convension)
Edit: if you really wanted to get complex, you can also merge the two approaches... Make a type trait to determine what type would be called from an overload, and use this to construct a function template of a specific underlying type.
This is similar to how variant needs to be implemented, since it has a U constructor that considers all types as an overload set:
// create an overload set of all functions, and return a unique index for
// each return type
template <std::size_t I, typename...Types>
struct overload_set_impl;
template <std::size_t I, typename T0, typename...Types>
struct overload_set_impl<I,T0,Types...>
: overload_set_impl<I+1,Types...>
{
using overload_set_impl<I+1,Types...>::operator();
std::integral_constant<std::size_t,I> operator()(T0);
};
template <typename...Types>
struct overload_set : overload_set_impl<0,Types...> {};
// get the index that would be returned from invoking all overloads with a T
template <typename T, typename...Types>
struct index_of_overload : decltype(std::declval<overload_set<Types...>>()(std::declval<T>())){};
// Get the element from the above test
template <typename T, typename...Types>
struct constructible_overload
: std::tuple_element<index_of_overload<T, Types...>::value, std::tuple<Types...>>{};
template <typename T, typename...Types>
using constructible_overload_t
= typename constructible_overload<T, Types...>::type;
And then use this with the second approach of having a function template:
template <typename...Types>
class MyClass {
public:
// still accept any type that is convertible
template <typename T, typename = std::enable_if_t<is_convertible_to_one_of<T, Types...>::value>>
void doSomething(const T& v)
{
// converts to the specific overloaded type, and call it
using type = constructible_overload_t<T, Types...>;
doSomethingImpl<type>(v);
}
private:
template <typename T>
void doSomethingImpl(const T&) { ... }
This last approach does it two-phase; it uses the first SFINAE condition to ensure it can be converted, and then determines the appropriate type to treat it as and delegates it to the real (private) implementation.
This is much more complex, but can achieve the overload-like semantics without actually requiring recursive implementation in the type creating it.
I found a few questions that ask something similar but could not find a straight answer for my particular case.
The whole syntax for Templates is very confusing to me so I may just misunderstood something.
I have a class template that is supposed to accept every type.
Simple example:
template <class T>
class State {
public:
void set(T newState);
T get();
private:
T state;
};
template <class T>
void State<T>::set(T newState){
state = newState;
}
template <class T>
T State<T>::get(){
return state;
}
Now I would like to have a specialised template for a group of types that adds an additional function for these types. From what I found out so far I can utilize so called type_traits but how exactly they are used to achieve this is still a mystery to me.
F.e. this specialization for the int type but instead of writing this just for the int type I would also like to allow all other int and float variants. I found std::is_arithmetic but have no Idea how to utilize it to achieve this.
template <>
class State <int> {
public:
void set(int newState);
int get();
int multiplyState(int n);
private:
int state;
};
void State<int>::set(int newState){
state = newState;
}
int State<int>::get(){
return state;
}
int State<int>::multiplyState(int n){
return state*n;
}
You can use partial template specialization in combination with SFINAE to achieve this:
#include <type_traits>
template <class T, typename = void>
class State
{
T state;
public:
void set(T newState)
{
state = newState;
}
T get()
{
return state;
}
};
template <typename T>
class State<T, std::enable_if_t<std::is_arithmetic_v<T>>>
{
T state;
public:
void set(int newState)
{
state = newState;
}
int get()
{
return state;
}
int multiplyState(int n)
{
return state*n;
}
};
live example here
The trick here lies in the use of the second template parameter (which can be unnamed and is given a default argument). When you use a specialization of your class template, e.g., State<some_type>, the compiler has to figure out which of the templates should be used. To do so, it has to somehow compare the given template arguments with each template and decide which one is the best match.
The way this matching is actually done is by trying to deduce the arguments of each partial specialization from the given template arguments. For example, in the case of State<int>, the template arguments are going to be int and void (the latter is there because of the default argument for the second parameter of the primary template). We then try to deduce the arguments for our sole partial specialization
template <typename T>
class State<T, std::enable_if_t<std::is_arithmetic_v<T>>>;
from the template arguments int, void. Our partial specialization has a single parameter T, which can directly be deduced from the first template argument to be int. And with that, we're already done as we have deduced all parameters (there is only one here). Now we substitute the deduced parameters into the partial specialization: State<T, std::enable_if_t<std::is_arithmetic_v<T>>>. We end up with State<int, void>, which matches the list of initial arguments of int, void. Therefore, the partial template specialization applies.
Now, if, instead, we had written State<some_type>, where some_type is not an arithmetic type, then the process would be the same up to the point where we have successfully deduced the parameter for the partial specialization to be some_type. Again, we substitute the parameter back into the partial specialization State<T, std::enable_if_t<std::is_arithmetic_v<T>>>. However, std::is_arithmetic_v<some_type> will now be false, which will lead to std::enable_if_t<…> not being defined and substitution fails. Since substituion failure is not an error in this context, this simply means that the partial specialization is not an option here and the primary template will be used instead.
If there were multiple matching partial specializations, they then would have to be ranked to pick the best match. The actual process is quite complicated, but it generally boils down to picking the most concrete specialization.
While for a small example like this it's fine to specialize the whole class, in more complicated cases you might be interested in avoiding having to duplicate all the members just so you can add one member to the specialization. To that end, a common technique is to inherit the extra member functions from a public base class, and specialize only the base class to either have or not have the members. You have to use CRTP so that the base class member functions know how to access the derived class. This looks like:
// StateBase only contains the extra multiplyState member when State tells it to
// define it, based on T being an arithmetic type
template <class D, class T, bool has_multiply>
struct StateBase {};
template <class D, class T>
struct StateBase<D, T, true> {
T multiplyState(int n) {
return static_cast<D*>(this)->state * n;
}
};
template <class T>
class State : public StateBase<State<T>, T, std::is_arithmetic<T>::value> {
public:
// no need to duplicate these declarations and definitions
void set(T newState);
T get();
private:
// note that we write State::StateBase to force the injected-class-name to be found
friend struct State::StateBase;
T state;
};
Coliru link
Assume that we have that struct X; and we use C++11 compiler (e.g. gcc 4.7). I'd like to emit some code and attributes if and only if, say, opt = true.
template <bool opt>
struct X {
void foo() {
EMIT_CODE_IF(opt) {
// optional code
}
// ...common code...
}
int optional_variable; // Emitted if and only if opt is true
};
As for the code, I assume that normal if suffices.
But as for the attributes, if one leaves them unused (when opt = false), will and COULD they be automatically omitted by the compiler? I definitely do not want them there when opt = false.
The approach to avoid attributes in a class template is to derive from a base class template which is specialized to be empty if the member shouldn't be there. For example:
template <bool Present, typename T>
struct attribute {
attribute(T const& init): attribute_(init) {}
T attribute_;
};
template <typename T>
struct attribute<false, T> {
};
template <bool opt>
class X: attribute<opt, int> {
...
};
With respect to optional code you may get away with a conditional statement but often the code wouldn't compile. In this case, you'd factor out the code into a suitable function object which be specialized to do nothing when not needed.