Say I have some class template:
template<typename T>
class {
// ....
}
I can partially specialize this template for ALL pointers by:
template<typename T>
class<T *> {
// ....
}
Can I somehow specialize the template for ALL enums? i.e., do something like:
(this doesn't work, though)
template<typename T>
class<enum T> {
// ....
}
use C++11 and SFINAE.
#include <type_traits>
template<typename T, typename = void>
struct Specialize
{
};
template<typename T>
struct Specialize<T, typename std::enable_if<std::is_enum<T>::value>::type>
{
void convert() { }
};
enum E
{
};
int main()
{
Specialize<E> spec;
spec.convert();
}
Without C++11 use boost::enable_if and boost::is_enum
Related
I want to create a function overload to partially specialize a template class. How to make this code work?
template <typename T>
struct Foo;
template <typename Result, typename ... Args>
struct Foo<Result(Args...)>
{
Result Bar()
{
Result t;
return t;
}
};
template <typename ... Args>
void Foo<void(Args...)>::Bar()
{
// do nothing;
}
If it's just a single member function that should expose different behavior if Result=void, then use tag-dispatching:
#include <type_traits>
template <typename T>
struct Foo;
template <typename Result, typename... Args>
struct Foo<Result(Args...)>
{
Result Bar()
{
return Bar(std::is_void<Result>{});
}
private:
Result Bar(std::false_type)
{
Result t;
// Do something
return t;
}
void Bar(std::true_type)
{
// Do nothing
}
};
DEMO
Alternatively, partially-specialize the whole class:
template <typename... Args>
struct Foo<void(Args...)>
{
void Bar()
{
// Do nothing
}
};
I have class like this:
template<typename T>
MyClass{
//myFunc();
}
I want to create myFunc method that return numeric value if class template is numeric and return nothing (void) when class template is not numeric.
For now, I got sth like this:
template<typename T>
MyClass{
template <typename returnT>
returnT myFunc();
}
template <typename T>
template <typename returnT>
typename std::enable_if<std::is_arithmetic<T>::value>
T MyClass<T>::myFunc()
{
return T::value;
}
template <typename T>
template <typename returnT>
typename std::enable_if<!std::is_arithmetic<T>::value>
void MyClass::myFunc()
{
//do sth
}
of course, that doesn't work. Is that a good idea to solve this problem this way? What is "smart" and working solution?
As an alternative to the constexpr if solution already supplied, here is your initial idea in it's working form.
#include <type_traits>
#include <iostream>
template<typename T>
struct MyClass{
template <typename returnT = T, std::enable_if_t<std::is_arithmetic_v<returnT>, bool> = true>
T myFunc();
template <typename returnT = T, std::enable_if_t<!std::is_arithmetic_v<returnT>, bool> = true>
void myFunc();
};
template <typename T>
template <typename returnT, std::enable_if_t<std::is_arithmetic_v<returnT>, bool>>
T MyClass<T>::myFunc()
{
std::cout << "yo\n";
return T{};
}
template <typename T>
template <typename returnT, std::enable_if_t<!std::is_arithmetic_v<returnT>, bool>>
void MyClass<T>::myFunc()
{
std::cout << "yay\n";
}
int main() {
MyClass<int> m;
MyClass<std::string> n;
m.myFunc();
n.myFunc();
}
The simplest way I can think of would be to just use if constexpr:
template <typename T>
class MyClass
{
auto myFunc()
{
if constexpr (std::is_arithmetic_v<T>)
{
return T{};
}
else
{
// do smth
}
}
};
If you can't use C++17, you will have to revert to some SFINAE-based approach. What that would best look like exactly depends a lot on what the actual signatures involved should be. But, for example, you could provide a partial class template specialization for the case of an arithmetic type:
template <typename T, typename = void>
class MyClass
{
void myFunc()
{
// do smth
}
};
template <typename T>
class MyClass<T, std::enable_if_t<std::is_arithmetic<T>::value>>
{
T myFunc()
{
return {};
}
};
Note that an arithmetic type cannot be a class type or enum, so I'm not sure what T::value was trying to achieve in your example code for the case of T being an arithmetic type…
I would create a helper template class to select the return type, and a helper function that uses overloading to perform the right behavior.
template <typename, bool> struct RType;
template <typename T> struct RType<T, false> { typedef void type; };
template <typename T> struct RType<T, true> { typedef T type; };
template<typename T>
class MyClass{
typedef RType<T, std::is_arithmetic<T>::value> R;
void myFuncT(RType<T, false>) {}
T myFuncT(RType<T, true>) { return 0; }
public:
typename R::type myFunc() { return myFuncT(R()); }
};
I want to do something like
template <typename T>
class TemporalAlarmDelay<T, std::enable_if<std::is_base_of<std::chrono::duration< , >, T>::value, T>::type>
{
public:
explicit TemporalAlarmDelay(T delay)
: mDelay(delay)
{
}
private:
T mDelay;
std::chrono::steady_clock::time_point mTriggerTime;
};
int main(int argc, char** args)
{
TemporalAlarmDelay<std::chrono::nanoseconds> nanosecondDelay; // this should work
TemporalAlarmDelay<std::chrono::milliseconds> millisecondDelay; // this should work
TemporalAlarmDelay<std::chrono::seconds> secondDelay; // this should work
TemporalAlarmDelay<int> failDelay; // fail to instantiate
}
The intent is to limit to types of std::chrono::duration (e.g std::chrono::milliseconds, std::chrono::seconds). What is the best way to go about this? As per my example, I was thinking I could use std::is_base_of, but I now realize that the helper types (e.g. std::chrono::milliseconds, std::chrono::seconds etc) do not use inheritance - derrr, what a silly thought.
And for the very simplest solution to your problem...
#include <chrono>
class TemporalAlarmDelay
{
public:
explicit TemporalAlarmDelay(std::chrono::steady_clock::duration delay)
: mDelay(delay)
{
}
private:
std::chrono::steady_clock::duration mDelay;
std::chrono::steady_clock::time_point mTriggerTime;
};
int main()
{
using namespace std::chrono_literals;
TemporalAlarmDelay nanosecondDelay{1ns}; // this works
TemporalAlarmDelay millisecondDelay{1ms}; // this works
TemporalAlarmDelay secondDelay{1s}; // this works
TemporalAlarmDelay failDelay{1}; // compile-time error
}
You can use template specialization:
template <typename T>
class TemporalAlarmDelay
{
~TemporalAlarmDelay() = delete; // prevent instantiation
};
template <typename R, typename P>
class TemporalAlarmDelay<std::chrono::duration<R, P>>
{
// your code
};
#Jarod42 suggests that you can even get away with:
template <typename> class TemporalAlarmDelay;
instead of the first four lines above.
You can create traits:
template <typename T> struct is_chrono_duration : std::false_type {};
template <typename R, typename P>
struct is_chrono_duration<std::chrono::duration<R, P>> : std::true_type {};
and then:
template <typename T>
class TemporalAlarmDelay
{
static_assert(is_chrono_duration<T>::value, "!");
// your code
};
Taking inspiration from the Jarod42's is_chrono_duration (well... copying it, to be honest), a possible SFINAE based (over a default boolean value) solution
template <typename T, bool = is_chrono_duration<T>::value>
class TmpAlrD;
template <typename T>
class TmpAlrD<T, true>
{
// ...
};
The following is a full compiling example
#include <chrono>
#include <type_traits>
template <typename>
struct is_chrono_duration : std::false_type
{ };
template <typename R, typename P>
struct is_chrono_duration<std::chrono::duration<R, P>> : std::true_type
{ };
template <typename T, bool = is_chrono_duration<T>::value>
class TmpAlrD;
template <typename T>
class TmpAlrD<T, true>
{
public:
explicit TmpAlrD(T delay = T{}) : mDelay(delay)
{ }
private:
T mDelay;
std::chrono::steady_clock::time_point mTriggerTime;
};
int main ()
{
TmpAlrD<std::chrono::nanoseconds> nsDelay; // compile
TmpAlrD<std::chrono::milliseconds> msDelay; // compile
TmpAlrD<std::chrono::seconds> sDelay; // compile
//TemporalAlarmDelay<int> // compilation error
}
How do one restrict the typename T to specific type?
Consider this:
template <typename T>
struct Worker {
// T can only be certain type allowing specific functionality.
// i.e T needs to be a product of some interface, support some functions, say T::toString(), T::print(), T::get().
// Do something with T
};
This is what I usually end up doing:
struct WorkableType {
std::string toString() { return ""; }
int get() { return 0;}
}
struct WorkabelTypeA : WorkableType {
std::string toString() { return "A"; }
int get() { return 1;}
};
//Similarly
struct WorkableTypeB : WorkableType;
And use static assert and std::is_base_of:
template <typename T>
struct Worker {
static_assert(std::is_base_of<WorkableType, T>::value, "Needs workable type");
// Do something with T
};
Is there any other design pattern, a more C++ way to restrict accidental instantiation of bad typed templates?
Edit: Seems like this would be better solved with C++ Concepts when it becomes the standard. Until then i guess, static_assert is probably more cleaner and verbose than enable_if.
You could use SFINAE and template specialisation:
// type trait that evaluates always to false to use in the primary template
template<typename ... T> struct always_false : std::false_type { };
// primary template
template<typename T, typename Enable = void>
struct Worker {
static_assert(always_false<T, Enable>::value, "Needs workable type");
};
// specialisation
template<typename T>
struct Worker<T, std::enable_if_t<std::is_base_of<WorkableType, T>::value>> {
...
};
You can create traits and check that in your class, So, no need of inheritance. For example:
template <typename T>
using toString_t = decltype(std::declval<T>().toString());
template <typename T>
using get_t = decltype(std::declval<T>().get());
// Use C++17, but can be done in C++11
template <typename T>
using has_toString = std::is_detected<toString_t, T>;
template <typename T>
using has_get = std::is_detected<get_t, T>;
And then
template <typename T>
struct Worker {
static_assert(has_toString<T>::value, "T should have toString");
static_assert(has_get<T>::value, "T should have get");
};
Demo
If you know exactly which types you want to allow, then a traits class is a succinct way to do it:
#include <utility>
// by default nothing is workable
template<class T>
struct is_workable : std::false_type
{
};
template <typename T>
struct Worker {
static_assert(is_workable<T>(), "not a workable type");
// T can only be certain type allowing specific functionality.
// i.e T needs to be a product of some interface, support some functions, say T::toString(), T::print(), T::get().
// Do something with T
};
// define a worker
struct A {};
// make it workable
template<> struct is_workable<A> : std::true_type {};
// define another worker but forget to make it workable
struct B {};
int main()
{
Worker<A> wa{};
// Worker<B> wb{}; // compile error - not workable
};
You can use specializations as it follows:
#include<string>
struct WorkableType {
std::string toString() { return ""; }
int get() { return 0; }
};
struct A {};
struct B {};
template<typename> struct Worker;
template<> struct Worker<A>: WorkableType {};
int main() {
Worker<A> wa;
// this won't compile
// Worker<B> wb;
}
Is it possible to do something like the following that compiles without template specialization?
template <class T>
class A {
public:
#if std::is_same<T, int>
void has_int() { }
#elif std::is_same<T, char>
void has_char() { }
#endif
};
A<int> a; a.has_int();
A<char> b; b.has_char();
Yes. Make the function templates and then conditionaly enable them using std::enable_if:
#include <type_traits>
template <class T>
class A {
public:
template<typename U = T>
typename std::enable_if<std::is_same<U,int>::value>::type
has_int() {}
template<typename U = T>
typename std::enable_if<std::is_same<U,char>::value>::type
has_char() {}
};
int main()
{
A<int> a;
a.has_int(); // OK
// a.has_char(); // error
}
The solution from the other answer might not be feasible if the class is big and has got many functions that need to regardless of T. But you can solve this by inheriting from another class that is used only for these special methods. Then, you can specialize that base class only.
In C++14, there are convenient type aliases so the syntax can become:
std::enable_if_t<std::is_same<U, int>::value>
And C++17, even shorter:
std::enable_if_t<std::is_same_v<U, int>>
Yes, with template specialization :
template <class T>
class A;
template <>
class A<int>
{
void had_int(){}
};
template <>
class A<char>
{
void had_char(){}
};