enable_if method specialization with implementation outside of class declaration - c++

I'm writing a templated singleton superclass, that can provide a thread-local instance or a process-global instance. The code below compiles and technically fits my need.
But, how can I write the function implementation outside of the class declaration? How do I declare the function in the class (is the commented line right)?
All similar questions implement the function in the class declaration.
#include <vector>
#include <type_traits>
using namespace std;
template <class t, bool tls=true>
class A{
public:
typedef std::vector<t> Avector;
// static Avector& getVector();
template <class T=t, bool TLS=tls, typename std::enable_if<!TLS>::type* = nullptr>
static Avector&
getVector(){
static Avector v=Avector();
return v;
}
template <class T=t, bool TLS=tls, typename std::enable_if<TLS>::type* = nullptr>
static Avector&
getVector(){
static thread_local Avector v=Avector();
return v;
}
};
int main(){
vector<int>& vi = A<int>::getVector();
vector<double>& vd = A<double, false>::getVector();
return 0;
}

You can instead write
template<typename T, bool>
struct A
{
typedef std::vector<T> Avector;
static Avector& getVector();
};
template<typename T, bool b>
typename A<T, b>::Avector& A<T, b>::getVector()
{
thread_local typename A<T, true>::Avector v;
return v;
}
template<typename T>
class A<T, false>
{
typedef std::vector<T> Avector;
static Avector& getVector();
};
template<typename T>
typename A<T, false>::Avector& A<T, false>::getVector()
{
static typename A<T, false>::Avector v;
return v;
}
Also, generally singletons shouldn't be used

I was searching an answer, and we got one on Stack Overflow 2 years after you posted your question, here : How to use std::enable_if on method of templated class with seperate declaration and definition via specialization.
First, you have to redefine the method as a template, with another typename, and with default value the class's template.
Second, you have to template<> 2 times on the implementation's side.
// hpp
template<typename T>
class A {
template <class U=T, typename std::enable_if_t<myCondition, bool>>
void myMethod();
}
// cpp
template<typename T>
template <class U=T, typename std::enable_if_t<myCondition, bool>>
void A::myMethod() {
// ...
}
If you don't want to define another template parameter, you can define the restriction as return type. Here we changed bool by void, but it can be whatever you want :
// hpp
template<typename T>
class A {
typename std::enable_if_t<myCondition, void>
myMethod();
}
// cpp
template<typename T>
typename std::enable_if_t<myCondition, void>
A::myMethod() {
// ...
}

Related

c++ templates overloading method depend on class type

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()); }
};

How do I declare SFINAE class?

Something is not working quite well for me. Is this the way to declare a class, that accepts only floating point template parameter?
template <typename T, swift::enable_if<std::is_floating_point<T>::value> = nullptr>
class my_float;
I fail to define methods outside this class. Doesn't compile, not sure why
Well... not exactly SFINAE... but maybe, using template specialization? Something as follows ?
template <typename T, bool = std::is_floating_point<T>::value>
class my_float;
template <typename T>
class my_float<T, true>
{
// ...
};
If you really want use SFINAE, you can write
template <typename T,
typename = typename std::enable_if<std::is_floating_point<T>::value>::type>
class my_float
{
// ...
};
or also (observe the pointer there isn't in your example)
template <typename T,
typename std::enable_if<std::is_floating_point<T>::value>::type * = nullptr>
class my_float // ------------------------------------------------^
{
};
-- EDIT --
As suggested by Yakk (thanks!), you can mix SFINAE and template specialization to develop different version of your class for different groups of types.
By example, the following my_class
template <typename T, typename = void>
class my_class;
template <typename T>
class my_class<T,
typename std::enable_if<std::is_floating_point<T>::value>::type>
{
// ...
};
template <typename T>
class my_class<T,
typename std::enable_if<std::is_integral<T>::value>::type>
{
// ...
};
is developed for in two versions (two different partial specializations), the first one for floating point types, the second one for integral types. And can be easily extended.
You can also use static_assert to poison invalid types.
template <typename T>
class my_float {
static_assert(std::is_floating_point<T>::value,
"T is not a floating point type");
// . . .
};
It's a little bit more direct, in my opinion.
With either of the other approaches, e.g.
template <typename T, bool = std::is_floating_point<T>::value>
class my_float;
template <typename T> class my_float<T, true> { /* . . . */ };
my_float<int,true> is a valid type. I'm not saying that that's a bad approach, but if you want to avoid this, you'll have to encapsulate
my_float<typename,bool> within another template, to avoid exposing the bool template parameter.
indeed, something like this worked for me (thanks to SU3's answer).
template<typename T, bool B = false>
struct enable_if {};
template<typename T>
struct enable_if<T, true> {
static const bool value = true;
};
template<typename T, bool b = enable_if<T,is_allowed<T>::value>::value >
class Timer{ void start(); };
template<typename T, bool b>
void Timer<T,b>::start()
{ \* *** \*}
I am posting this answer because I did not want to use partial specialization, but only define the behavior of the class outside.
a complete workable example:
typedef std::integral_constant<bool, true> true_type;
typedef std::integral_constant<bool, false> false_type;
struct Time_unit {
};
struct time_unit_seconds : public Time_unit {
using type = std::chrono::seconds;
};
struct time_unit_micro : public Time_unit {
using type = std::chrono::microseconds;
};
template<typename T, bool B = false>
struct enable_if {
};
template<typename T>
struct enable_if<T, true> {
const static bool value = true;
};
template<typename T,
bool b = enable_if<T,
std::is_base_of<Time_unit,
T>::value
>::value>
struct Timer {
int start();
};
template<typename T, bool b>
int Timer<T, b>::start() { return 1; }
int main() {
Timer<time_unit_seconds> t;
Timer<time_unit_micro> t2;
// Timer<double> t3; does not work !
return 0;
}

std::tuple of std::shared_ptr of template parameter pack

I want to implement a class template that:
behaves like a function
it's input and output variables are all shared.
relatively easy to use.
As a result, I construct the following:
// all input/output variable's base class
class basic_logic_parameter;
// input/output variable, has theire value and iterators to functions that reference to this variable
template <typename FuncIterator, typename ValueType>
class logic_parameter
:public basic_logic_parameter
{
private:
std::list<FuncIterator> _refedFuncs;
ValueType _val;
public:
};
// all `function`'s base class
class basic_logic_function
{
public:
virtual ~basic_logic_function() = 0;
};
// the function, has input/output variable
template <typename FuncIterator, typename R, typename... Args>
class logic_function_base
:public basic_logic_function
{
private:
std::shared_ptr<logic_parameter<FuncIterator, R>> _ret;
std::tuple<std::shared_ptr<logic_parameter<FuncIterator, Args>>...> _args;
public:
template <std::size_t N>
decltype(auto) arg()
{
return std::get<N>(_args);
}
template <std::size_t N>
struct arg_type
{
typedef std::tuple_element_t<N> type;
};
template <std::size_t N>
using arg_type_t = arg_type<N>::type;
decltype(auto) ret()
{
return _ret;
}
};
I wish to use as these like:
// drawing need color and a pen
struct Color
{
};
struct Pen
{
};
struct Iter
{
};
class Drawer
:public logic_function_base<Iter, void(Color, Pen)>
{
public:
void draw()
{
arg_type_t<0> pColor; // wrong
}
}
My compiler can not pass this code through, why? I just want convert a template parameter pack to std::tuple of std::shared_ptr of them.
for example:
Given struct A, int, struct C, I want to have:
std::tuple<
std::shared_ptr<logic_parameter<A>>,
std::shared_ptr<logic_parameter<int>>,
std::shared_ptr<logic_parameter<C>>,
>
The problem (once the small errors are fixed1) is that you instantiate:
logic_function_base<Iter, void(Color, Pen)>
...meaning that FuncIterator is Iter and R is void(Color, Pen), so Args is emtpy <>, so decltype(_args) is an empty std::tuple<>, and your code fails to obtain the type of the 0th element of an empty tuple, which is legit.
What you want is partial specialization of logic_function_base:
template <typename F, typename T>
class logic_function_base;
template <typename FuncIterator, typename R, typename... Args>
class logic_function_base<FuncIterator, R(Args...)>: public basic_logic_function {
};
1 Small mistakes in your current code:
template <std::size_t N>
struct arg_type
{
typedef std::tuple_element_t<N, decltype(_args)> type; // Missing the tuple type
};
template <std::size_t N>
using arg_type_t = typename arg_type<N>::type; // Missing a typename
This may not answer your whole question, but you could use the following trait to wrap tuple element types.
template <typename T> struct wrap;
template <typename... T>
struct wrap<std::tuple<T...>> {
using type = std::tuple<std::shared_ptr<logic_parameter<T>>...>;
}
template <typename T>
using wrap_t = typename wrap<T>::type;
You can then use it like this:
std::tuple<int,double,char> t1;
wrap_t<decltype(t)> t2;
The type of t2 is std::tuple<std::shared_ptr<logic_parameter<int>>,std::shared_ptr<logic_parameter<double>>,std::shared_ptr<logic_parameter<char>>>.

How to implement is_polymorphic_functor?

I'm trying to implement is_polymorphic_functor meta-function to get the following results:
//non-polymorphic functor
template<typename T> struct X { void operator()(T); };
//polymorphic functor
struct Y { template<typename T> void operator()(T); };
std::cout << is_polymorphic_functor<X<int>>::value << std::endl; //false
std::cout << is_polymorphic_functor<Y>::value << std::endl; //true
Well that is just an example. Ideally, it should work for any number of parameters, i.e operator()(T...). Here are few more test cases which I used to test #Andrei Tita's solution which fails for two test-cases.
And I tried this:
template<typename F>
struct is_polymorphic_functor
{
private:
typedef struct { char x[1]; } yes;
typedef struct { char x[10]; } no;
static yes check(...);
template<typename T >
static no check(T*, char (*) [sizeof(functor_traits<T>)] = 0 );
public:
static const bool value = sizeof(check(static_cast<F*>(0))) == sizeof(yes);
};
which attempts to make use of the following implementation of functor_traits:
//functor traits
template <typename T>
struct functor_traits : functor_traits<decltype(&T::operator())>{};
template <typename C, typename R, typename... A>
struct functor_traits<R(C::*)(A...) const> : functor_traits<R(C::*)(A...)>{};
template <typename C, typename R, typename... A>
struct functor_traits<R(C::*)(A...)>
{
static const size_t arity = sizeof...(A) };
typedef R result_type;
template <size_t i>
struct arg
{
typedef typename std::tuple_element<i, std::tuple<A...>>::type type;
};
};
which gives the following error for polymorphic functors:
error: decltype cannot resolve address of overloaded function
How to fix this issue and make is_polymorphic_functor work as expected?
This works for me:
template<typename T>
struct is_polymorphic_functor
{
private:
//test if type U has operator()(V)
template<typename U, typename V>
static auto ftest(U *u, V* v) -> decltype((*u)(*v), char(0));
static std::array<char, 2> ftest(...);
struct private_type { };
public:
static const bool value = sizeof(ftest((T*)nullptr, (private_type*)nullptr)) == 1;
};
Given that the nonpolymorphic functors don't have an overloaded operator():
template<typename T>
class is_polymorphic_functor {
template <typename F, typename = decltype(&F::operator())>
static constexpr bool get(int) { return false; }
template <typename>
static constexpr bool get(...) { return true; }
public:
static constexpr bool value = get<T>(0);
};
template<template<typename>class arbitrary>
struct pathological {
template<typename T>
typename std::enable_if< arbitrary<T>::value >::type operator(T) const {}
};
The above functor is non-polymorphic iff there is exactly one T such that arbitrary<T>::value is true.
It isn't hard to create an template<T> functor which is true on int and possibly double, and only true on double if (arbitrary computation returns 1).
So an uncompromising is_polymorphic is beyond the scope of this universe.
If you don't like the above (because it clearly takes more than just int, other types simply fail to find an overload), we could do this:
template<template<typename>class arbitrary>
struct pathological2 {
void operator()(int) const {}
template<typename T>
typename std::enable_if< arbitrary<T>::value >::type operator(T) const {}
};
where the second "overload" is tested, and if there are no T such that it is taken, then the first overload occurs for every single type.

detecting typedef at compile time (template metaprogramming)

I am currently doing some template metaprogramming. In my case I can handle any "iteratable" type, i.e. any type for which a typedef foo const_iterator exists in the same manner. I was trying to use the new C++11 template metaprogramming for this, however I could not find a method to detect if a certain type is missing.
Because I also need to turn on/off other template specializations based on other characteristics, I am currently using a template with two parameters, and the second one gets produced via std::enable_if. Here is what I am currently doing:
template <typename T, typename Enable = void>
struct Foo{}; // default case is invalid
template <typename T>
struct Foo< T, typename std::enable_if<std::is_fundamental<T>::value>::type>{
void do_stuff(){ ... }
};
template<typename T>
struct exists{
static const bool value = true;
};
template<typename T>
struct Foo<T, typename std::enable_if<exists< typename T::const_iterator >::value >::type> {
void do_stuff(){ ... }
};
I was not able to do something like this without the exists helper template. For example simply doing
template<typename T>
struct Foo<T, typename T::const_iterator> {
void do_stuff(){ ... }
};
did not work, because in those cases where this specialization should be used, the invalid default case was instantiated instead.
However I could not find this exists anywhere in the new C++11 standard, which as far as I know simply is taking from boost::type_traits for this kind of stuff. However on the homepage for boost::type_traits does not show any reference to anything that could be used instead.
Is this functionality missing, or did I overlook some other obvious way to achieve the desired behavior?
If you simply want if a given type contains const_iterator then following is a simplified version of your code:
template<typename T>
struct void_ { typedef void type; };
template<typename T, typename = void>
struct Foo {};
template<typename T>
struct Foo <T, typename void_<typename T::const_iterator>::type> {
void do_stuff(){ ... }
};
See this answer for some explanation of how this technique works.
You can create a trait has_const_iterator that provides a boolean value and use that in the specialization.
Something like this might do it:
template <typename T>
struct has_const_iterator {
private:
template <typename T1>
static typename T1::const_iterator test(int);
template <typename>
static void test(...);
public:
enum { value = !std::is_void<decltype(test<T>(0))>::value };
};
And then you can specialize like this:
template <typename T,
bool IsFundamental = std::is_fundamental<T>::value,
bool HasConstIterator = has_const_iterator<T>::value>
struct Foo; // default case is invalid, so no definition!
template <typename T>
struct Foo< T, true, false>{
void do_stuff(){// bla }
};
template<typename T>
struct Foo<T, false, true> {
void do_stuff(){//bla}
};
Here's another version of a member type trait check:
template<typename T>
struct has_const_iterator
{
private:
typedef char yes;
typedef struct { char array[2]; } no;
template<typename C> static yes test(typename C::const_iterator*);
template<typename C> static no test(...);
public:
static const bool value = sizeof(test<T>(0)) == sizeof(yes);
};
There is a couple of ways to do this. In C++03, you could use boost and enable_if to define the trait (docs, source):
BOOST_MPL_HAS_XXX_TRAIT_DEF(const_iterator);
template <typename T, typename Enable = void>
struct Foo;
template <typename T>
struct Foo< T, typename boost::enable_if<boost::is_fundamental<T> >::type>{
void do_stuff(){ ... }
};
template<typename T>
struct Foo<T, typename boost::enable_if<has_const_iterator<T> >::type> {
void do_stuff(){ ... }
};
In C++11, you could use Tick like this:
TICK_TRAIT(has_const_iterator)
{
template<class T>
auto require(const T&) -> valid<
has_type<typename T::const_iterator>
>;
};
template <typename T, typename Enable = void>
struct Foo;
template <typename T>
struct Foo< T, TICK_CLASS_REQUIRES(std::is_fundamental<T>::value)>{
void do_stuff(){ ... }
};
template<typename T>
struct Foo<T, TICK_CLASS_REQUIRES(has_const_iterator<T>())> {
void do_stuff(){ ... }
};
Also with Tick you can further enhance the trait to actually detect that the const_iterator is actually an iterator, as well. So say we define a simple is_iterator trait like this:
TICK_TRAIT(is_iterator,
std::is_copy_constructible<_>)
{
template<class I>
auto require(I&& i) -> valid<
decltype(*i),
decltype(++i)
>;
};
We can then define has_const_iterator trait to check that the const_iterator type matches the is_iterator trait like this:
TICK_TRAIT(has_const_iterator)
{
template<class T>
auto require(const T&) -> valid<
has_type<typename T::const_iterator, is_iterator<_>>
>;
};