I want to have some compile time if. But I can't just put if statement because compiler will check both branches, and one of branches may be invalid (call not existing in this case function, etc..).
In other words I want #ifdef
but in templates. Consider helper/wrapper of this. So, I write the following templated class, which expect bool argument. "true" specialization call one function, "false" - another:
#define MAKE_IF(c_name, fn1, fn2)\
template<bool select, class DUMMY = void>\
struct c_name{\
}; \
\
template<class DUMMY>\
struct c_name<true, DUMMY>{\
template<typename SELF, typename ...Args>\
static auto fire(SELF &&self, Args &&...args)-> decltype( self.fn1(std::forward<Args>(args)...) ){\
return self.fn1( std::forward<Args>(args)... );\
}\
};\
\
template<class DUMMY>\
struct c_name<false, DUMMY>{\
template<typename SELF, typename ...Args>\
static auto fire(SELF &&self, Args &&...args) -> decltype( self.fn2(std::forward<Args>(args)...) ) {\
return self.fn2( std::forward<Args>(args)...);\
}\
};
/// Usage:
MAKE_IF(selector, fn1, fn2 )
selector<do_it>::fire(*this);
All good, all work. But I want to get rid of this #define
s, so I make the following thing (lambda based):
template<bool select, class DUMMY = void>
struct CONDITION_HELPER{};
template<class DUMMY>
struct CONDITION_HELPER<true, DUMMY>{
template<class FN1, class FN2>
static auto fire(FN1 &&fn1, FN2 &&) -> decltype( fn1() ){
return fn1();
}
};
template<class DUMMY>
struct CONDITION_HELPER<false, DUMMY>{
template<class FN1, class FN2>
static auto fire(FN1 &&, FN2 &&fn2) -> decltype( fn2() ){
return fn2();
}
};
template<bool first, class FN1, class FN2>
auto if_else(FN1 &&fn1, FN2 &&fn2) -> decltype(
CONDITION_HELPER<first>::fire(
std::forward<FN1>(fn1),
std::forward<FN2>(fn2)
)
){
return CONDITION_HELPER<first>::fire(
std::forward<FN1>(fn1),
std::forward<FN2>(fn2)
);
}
//Usage:
if_else<do_it>(
[&]{ return fn1(data); },
[&]{ return fn2(data); }
);
And this does not work. On the line with the lambdas I get the error
main.cpp:111:37: error: non-const lvalue reference to type 'B' cannot bind to a value of unrelated type 'A'
[&]{ return fn1(data); },
Complete code: