SFINAE for class member overload methods - c++

Consider this snippet:
#include <type_traits>
struct UseMap;
struct NoMap;
template<typename MapType = NoMap>
class MyClass
{
public:
typename std::enable_if<std::is_same<MapType, NoMap>::value, bool>::type
handleEvent(int someVal)
{
return doSomething();
}
typename std::enable_if<std::is_same<MapType, UseMap>::value, bool>::type
handleEvent(int someVal)
{
return doSomethingDifferent();
}
bool doSomething() {};
bool doSomethingDifferent() {};
};
int main() {
MyClass obj1();
MyClass<UseMap> obj2();
return 0;
}
Is it possible to compile only one handleEvent method, depending on the provided template class type?
With the example above the compiler gives:
prog.cpp:18:3: error: 'typename std::enable_if<std::is_same<MapType, UseMap>::value, bool>::type MyClass<MapType>::handleEvent(int)' cannot be overloaded

I think you have to make the overloaded functions template.
template<typename T = MapType,
typename std::enable_if<
std::is_same<T, NoMap>::value>::type *& = nullptr>
bool
handleEvent(int someVal)
{
return doSomething();
}
template<typename T = MapType,
typename std::enable_if<
std::is_same<T, UseMap>::value>::type *& = nullptr>
bool
handleEvent(int someVal)
{
return doSomethingDifferent();
}
This passes compile. (clang-600.0.54 with -std=c++11)

Complement to findall's answer : you can also inherit from an easily specializable base class.
struct UseMap;
struct NoMap;
template<typename>
class MyClass;
namespace detail {
// Container for the handleEvent() function
template<typename>
struct MyClassHandler;
}
// Enter CRTP !
template<typename MapType = NoMap>
class MyClass : detail::MyClassHandler<MyClass<MapType>>
{
friend class detail::MyClassHandler<MyClass<MapType>>;
public:
using detail::MyClassHandler<MyClass<MapType>>::handleEvent;
bool doSomething() {};
bool doSomethingDifferent() {};
};
// Actual specializations now that the full definition of MyClass is in scope
namespace detail {
template<>
struct MyClassHandler<MyClass<NoMap>> {
bool handleEvent(int someVal)
{
return static_cast<MyClass<NoMap>*>(this)->doSomething();
}
};
template<>
struct MyClassHandler<MyClass<UseMap>> {
bool handleEvent(int someVal)
{
return static_cast<MyClass<UseMap>*>(this)->doSomethingDifferent();
}
};
}
I feel like I overcomplicated the declaration order a bit, double-check welcome :)

Related

Need a way to check template type and if not in the range of allowed types then have compile time error in C++

I need to have a template class where each object adds itself to a vector and based on the template type parameter(allowed only: string, int, float) add to the corresponding container. I need a way to have compile time checks for the type and based on the check add to the corresponding container and if the type is not one of the allowed types compile time error should be emitted.
Example: code
vector<myClass<int>*> intVec;
vector<myClass<float>*> floatVec;
vector<myClass<string>*> stringVec;
template<typename T>
struct myClass
{
myClass()
{
/*pseudo code
if(T == int) {
intVec.push_back(this);
}
else if(T == float) {
floatVec.push_back(this);
}
else if(T == string){
stringVec.push_back(this);
}
else {
// error
}
*/
}
T value;
}
How can I achieve this ?
In C++17 and later, you can use if constexpr and std::is_same_v, eg:
#include <type_traits>
template<typename T>
struct myClass
{
myClass()
{
if constexpr (std::is_same_v<T, int>) {
m_intVec.push_back(this);
}
else if constexpr (std::is_same_v<T, float>) {
m_floatVec.push_back(this);
}
else if constexpr (std::is_same_v<T, std::string>){
m_stringVec.push_back(this);
}
else {
// error
}
}
T value;
};
In earlier versions, you can use either template specialization or SFINAE instead, eg:
// via specialization
template<typename T>
struct myClass
{
};
template<>
struct myClass<int>
{
myClass()
{
m_intVec.push_back(this);
}
int value;
};
template<>
struct myClass<float>
{
myClass()
{
m_floatVec.push_back(this);
}
float value;
};
template<>
struct myClass<std::string>
{
myClass()
{
m_stringVec.push_back(this);
}
std::string value;
};
// via SFINAE
#include <type_traits>
template<typename T>
struct myClass
{
template<typename U = T, std::enable_if<std::is_same<U, int>::value, int>::type = 0>
myClass()
{
m_intVec.push_back(this);
}
template<typename U = T, std::enable_if<std::is_same<U, float>::value, int>::type = 0>
myClass()
{
m_floatVec.push_back(this);
}
template<typename U = T, std::enable_if<std::is_same<U, std::string>::value, int>::type = 0>
myClass()
{
m_stringVec.push_back(this);
}
T value;
};
Use specialization and a helper function, e.g.
template<typename T>
struct myClass;
inline std::vector<myClass<int>*> intVec;
inline std::vector<myClass<float>*> floatVec;
inline std::vector<myClass<std::string>*> stringVec;
template<typename T>
void add(myClass<T>*);
template<>
void add(myClass<int>* p) {
intVec.push_back(p);
}
template<>
void add(myClass<float>* p) {
floatVec.push_back(p);
}
template<>
void add(myClass<std::string>* p) {
stringVec.push_back(p);
}
template<typename T>
struct myClass
{
myClass()
{
add(this);
}
T value;
};
in addition to existing answers, you can also do it with normal function overloading
template<typename T>
struct myClass;
inline std::vector<myClass<int>*> intVec;
inline std::vector<myClass<float>*> floatVec;
inline std::vector<myClass<std::string>*> stringVec;
/* optional
template<typename T>
constexpr bool always_false = false;
template<typename T>
void add(myClass<T>*) {
static_assert(always_false<T>,"unsupported T");
}
*/
void add(myClass<int>* p) {
intVec.push_back(p);
}
void add(myClass<float>* p) {
floatVec.push_back(p);
}
void add(myClass<std::string>* p) {
stringVec.push_back(p);
}
template<typename T>
struct myClass
{
myClass()
{
add(this);
}
T value;
};

Accessing functions of a derived crtp class from the base calls

I need to be able to access a static method of the derived class, from within a base CRTP class. Is there a way in which I can achieve this?
Here is example code:
#define REQUIRES(...) std::enable_if_t<(__VA_ARGS__), bool> = true
template<typename Derived>
struct ExpressionBase {
Derived& derived() { return static_cast<Derived&>(*this); }
const Derived& derived() const { return static_cast<const Derived&>(*this); }
constexpr static int size()
{
return Derived::size();
}
template<typename T, REQUIRES(size() == 1)>
operator T() const;
};
struct Derived : public ExpressionBase<Derived>
{
constexpr static int size()
{
return 1;
}
};
Deriving from ExpressionBase<Derived> involves the instantiation of ExpressionBase<Derived>, therefore involves the declaration of the entity
template<typename T, REQUIRES(size() == 1)>
operator T() const;
Here, std::enable_if_t got a template argument that is ill-formed (because Derived isn't complete yet). The SFINAE rule does not apply here, because the ill-formed expression is not in direct context of template argument type, thus it is treated as a hard error.
In order to make the ill-formation happen at an immediate context, use the following code:
#include <type_traits>
template <bool B, class T>
struct lazy_enable_if_c {
typedef typename T::type type;
};
template <class T>
struct lazy_enable_if_c<false, T> {};
template <class Cond, class T>
struct lazy_enable_if : public lazy_enable_if_c<Cond::value, T> {};
template <class T>
struct type_wrapper {
using type = T;
};
#define REQUIRES(...) std::enable_if_t<(__VA_ARGS__), bool> = true
template<typename Derived>
struct ExpressionBase {
Derived& derived() { return static_cast<Derived&>(*this); }
const Derived& derived() const { return static_cast<const Derived&>(*this); }
struct MyCond {
static constexpr bool value = Derived::size() == 1;
};
template<typename T, typename = typename lazy_enable_if<MyCond, type_wrapper<T>>::type>
operator T () const {
return T{};
}
};
struct Derived : public ExpressionBase<Derived>
{
constexpr static int size() {
return 1;
}
};
int main() {
Derived d;
int i = d;
return 0;
}
It is actually adapted from boost, which you can find more details here.

boost::variant and polymorphism

I want to get pointer to base class from boost variant, if I put orignally pointer to derived class. Is there some way to achive this . The following code does not work.
class A{ public: virtual ~A(){}}; class B : public A{};
typedef boost::variant<A*,B*> MyVar;
MyVar var = new B;
A* a = boost::get<A*> (var); // the following line throws exception
Maybe someone have idea how to write my own get function which will test if the requested type is base class of the stored type of in the variant,and then do the appropriate cast
You can write your own visitor with templated operator() like below:
LIVE DEMO
#include <iostream>
#include <boost/variant.hpp>
#include <type_traits>
struct A { virtual ~A() {} virtual void foo() {} };
struct B : A { virtual void foo() { std::cout << "B::foo()" << std::endl; } };
template <typename T>
struct visitor : boost::static_visitor<T>
{
private:
using Base = typename std::remove_pointer<
typename std::remove_cv<
typename std::remove_reference<T>::type
>::type
>::type;
template <typename U>
T get(U& u, std::true_type) const
{
return u;
}
template <typename U>
T get(U& u, std::false_type) const
{
throw boost::bad_get{};
}
public:
template <typename U>
T operator()(U& u) const
{
using Derived = typename std::remove_pointer<
typename std::remove_cv<
typename std::remove_reference<U>::type
>::type
>::type;
using tag = std::integral_constant<bool
, (std::is_base_of<Base, Derived>::value
|| std::is_same<Base, Derived>::value)
&& std::is_convertible<U, T>::value>;
return get(u, tag{});
}
};
template <typename T, typename... Args>
T my_get(boost::variant<Args...>& var)
{
return boost::apply_visitor(visitor<T>{}, var);
}
int main()
{
boost::variant<A*,B*> var = new B;
A* a = my_get<A*>(var); // works!
a->foo();
B* b = my_get<B*>(var); // works!
b->foo();
}
Output:
B::foo()
B::foo()
Q & A section:
This solution is weird!
No, it is not. This is exactly what the visitor classes in Boost.Variant are for. Similar solution already exists in latest release of Boost.Variant, which is boost::polymorphic_get<T>. Sadly it was designed for other purposes and cannot be used here.
Hi thank you all for your answers and comments
I came to the following which decides at compile time if types are inherited from each other. And it seems to work, and it seems much easier to me to understand.
#include <iostream>
#include <boost/variant.hpp>
#include <boost/type_traits.hpp>
#include <boost/utility.hpp>
using namespace boost::type_traits;
struct A { virtual ~A() {} virtual void foo() {} };
struct B : A { virtual void foo() { std::cout << "B::foo()" << std::endl; } };
typedef boost::variant<B*,A*,C*> MyVar;
template <typename A,typename B>
struct types_are_inheritance_related
{
static const bool value=
ice_or<
boost::is_base_of<A, B>::value,
boost::is_base_of<B, A>::value
>::value;
};
template<class Base>
class get_visitor
: public boost::static_visitor<Base*> { public:
template<class T>
Base* operator()( T* t, typename boost::enable_if<types_are_inheritance_related<Base,T> >::type* dummy = 0)
{
Base* b = dynamic_cast<Base*> ( t);
return b;
}
template<class T>
Base* operator()( T* t, typename boost::disable_if<types_are_inheritance_related<Base,T> >::type* dummy = 0)
{
return 0;
}
};
template<class T>
T* get_var_value(MyVar& var)
{
get_visitor<T> visitor;
T* aa= var.apply_visitor(visitor);
return aa;
}
int main()
{
MyVar var = new B;
A* a = get_var_value<A*>(var); // works!
a->foo();
B* b = get_var_value<B*>(var); // works!
b->foo();
}

accessing members of a templated class with variable numbers of templated arguments

I have a templated class with variable numbers of templated arguments. As in these cases (I cannot afford C++11) a good practice is to create a default class that we call none and put it as default like below.
struct none {};
template<class T1=none, T2=none, T3=none>
class A{
template<class T>
double extract() { return none();}
template<>
double extract<T1>() { return m1_();}
template<>
double extract<T2>() { return m2_();}
template<>
double extract<T3> () { return m3_();}
T1 m1_;
T2 m2_;
T3 m3_;
};
At this stage I don't know how to implement a generic/templated accessor function that can access each of the templated argument.
All of the templated arguments are different so I specialized A::extract() for each of the templated arguments.
Is there any better way to do this? Any sort of tagging I can have a look at?
struct none {};
template <class T, class N>
class Holder : public N
{
protected:
T m;
typedef Holder<T, N> First;
double extractP(T*) { return m(); }
template <class X> double extractP(X*) {
return this->N::extractP(static_cast<X*>(0));
}
};
template <class T>
class Holder<T, none>
{
protected:
T m;
typedef Holder<T, none> First;
double extractP(T*) { return m(); }
template <class X> none extractP(X*) {
return none();
}
};
template <class T1 = none, class T2 = none, class T3 = none>
class A : Holder<T1, Holder<T2, Holder<T3, none> > >
{
public:
template <class T> double extract() {
return this->extractP(static_cast<T*>(0));
}
};
A similarly-named solution to n.m but more on the Boost's Variant class design.
The suggestion is to use a Variant container (a generic container for your objects) and use accessors directly on them.
#include <iostream>
#include <stdexcept>
using namespace std;
class BaseHolder
{
public:
virtual ~BaseHolder(){}
virtual BaseHolder* clone() const = 0;
};
template<typename T>
class HoldData : public BaseHolder
{
public:
HoldData(const T& t_) : t(t_){}
virtual BaseHolder* clone() const {
return new HoldData<T>(t);
}
T getData() {
return t;
}
private:
T t;
};
class Variant
{
public:
Variant() : data(0) {}
template<typename T>
Variant(const T& t) : data(new HoldData<T>(t)){}
Variant(const Variant& other) : data(other.data ? other.data->clone() : 0) {}
~Variant(){delete data;}
template<typename T>
T getData() {
return ((HoldData<T>*)data)->getData();
}
private:
BaseHolder* data;
private:
Variant& operator=(const Variant& other) { return *this;} // Not allowed
};
struct none {};
class Container{
public:
Container() : m1_(0), m2_(0), m3_(0){}
~Container() {
if(m1_)
delete m1_;
if(m2_)
delete m1_;
if(m3_)
delete m1_;
}
none extract() { return none();}
template<typename T>
void insertM1(T obj) {
m1_ = new Variant(obj);
}
template<typename T>
T extractM1() {
if(m1_ != 0)
return m1_->getData<T>();
else
throw std::runtime_error("Element not set");
}
// TODO: implement m2 and m3
Variant *m1_;
Variant *m2_;
Variant *m3_;
};
int main() {
Container obj;
char M1 = 'Z';
obj.insertM1(M1);
char extractedM1 = obj.extractM1<char>();
cout << extractedM1;
return 0;
}
http://ideone.com/BaCWSV
Your class seems to mimic std::tuple, which, unfortunately for you, was added in C++11. The good news is that you can use boost::tuple instead.
As an example of usage:
boost::tuple<std::string, double> t = boost::make_tuple("John Doe", 4.815162342);
std::cout << boost::get<0>(t) << '\n';
std::cout << boost::get<1>(t) << '\n';
Live demo
Without access to C++11, it's a bit uglier, but you can leverage Boost.Tuple:
#include <iostream>
#include <boost/tuple/tuple.hpp>
template <size_t I, typename T, typename U>
struct AccessImpl;
template <size_t I, typename T, typename U>
struct AccessImpl {
template <typename Tuple>
static T& impl(Tuple& tuple) {
typedef typename ::boost::tuples::element<I+1, Tuple>::type Next;
return AccessImpl<I+1, T, Next>::impl(tuple);
}
};
template <size_t I, typename T>
struct AccessImpl<I, T, T> {
template <typename Tuple>
static T& impl(Tuple& tuple) { return boost::get<I>(tuple); }
};
template <typename T, typename Tuple>
T& access(Tuple& tuple) {
typedef typename ::boost::tuples::element<0, Tuple>::type Head;
return AccessImpl<0, T, Head>::impl(tuple);
}
int main() {
boost::tuples::tuple<char, int, std::string> example('a', 1, "Hello, World!");
std::cout << access<std::string>(example) << "\n";
return 0;
}
This, as expected, prints "Hello, World!".

boost concept check operator() overload

template <typename T, typename C>
class CSVWriter{
template <typename PrinterT>
void write(std::ostream& stream, const PrinterT& printer){
}
};
I want to check whether there exists at least two overloads PrinterT::operator()(T*) and PrinterT::operator()(C*)
PrinterT may or may not inherit from std::unary_function
What concept Checking Classes I need to use here ?
(I am not using C++11)
You can use something like that
#include <iostream>
#include <boost/concept/requires.hpp>
#include <boost/concept/usage.hpp>
template <class Type, class Param>
class has_operator_round_brackets_with_parameter
{
public:
BOOST_CONCEPT_USAGE(has_operator_round_brackets_with_parameter)
{
_t(_p);
}
private:
Type _t;
Param _p;
};
struct X {};
struct Y {};
struct Test1
{
void operator() (X*) const { }
};
struct Test2: public Test1
{
void operator() (X*) const { }
void operator() (Y*) const { }
};
template <class T, class C>
struct CSVWriter
{
template <class PrinterT>
BOOST_CONCEPT_REQUIRES(
((has_operator_round_brackets_with_parameter<PrinterT, T*>))
((has_operator_round_brackets_with_parameter<PrinterT, C*>)),
(void)) write(std::ostream& stream, const PrinterT& printer)
{
}
};
int main()
{
CSVWriter<X, Y> w;
// w.write<Test1>(std::cout, Test1()); // FAIL
w.write<Test2>(std::cout, Test2()); // OK
return 0;
}