0

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 #defines, 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:

http://coliru.stacked-crooked.com/a/6756e1716c043ba0

Community
  • 1
  • 1
tower120
  • 5,007
  • 6
  • 40
  • 88
  • I think of it, but I can't pass variadic param list with `enable_if` in first case. Look "Complete code", I pass data to functions. – tower120 Jun 27 '14 at 16:58
  • @tower120: Sure you can, just not after the variadic parameters – Mooing Duck Jun 27 '14 at 17:01
  • 2
    When things get this complicated, reconsider your original design. – Neil Kirk Jun 27 '14 at 17:02
  • put additional template param BEFORE ...Args? I tried that not worked. Can you show example? – tower120 Jun 27 '14 at 17:02
  • And even if I change this to `enable_if` - what change this? – tower120 Jun 27 '14 at 17:04
  • Can you try using tag dispatch instead? – Simple Jun 27 '14 at 17:08
  • I'll try now, but what it change? – tower120 Jun 27 '14 at 17:11
  • Tried with `enable_if` http://coliru.stacked-crooked.com/a/67cb82f6f5f10403 the same error. – tower120 Jun 27 '14 at 17:17
  • GAH! I JUST FINISHED LIKE A TWO PAGE ANSWER AND ITS CLOSED! http://coliru.stacked-crooked.com/a/c3f5cf1668f5cfb9 That being said, yes it is a dupe :( – Mooing Duck Jun 27 '14 at 17:26
  • @tower120: I don't see enable_if anywhere in that code. (Also, lambdas are not going to work for this, period) No wait, I figured out how to lambda! – Mooing Duck Jun 27 '14 at 17:28
  • 1
    If the lambdas take the input as a parameter, then you can use simple tag dispatching: http://coliru.stacked-crooked.com/a/02527b48e86c08eb – Mooing Duck Jun 27 '14 at 17:37
  • Why I can't change it to decltype http://coliru.stacked-crooked.com/a/fd73a1dce5367c5a ? – tower120 Jun 27 '14 at 17:43
  • 1
    @MooingDuck [Put the argument after the function parameters and make it variadic, and you have a reasonably general solution](http://coliru.stacked-crooked.com/a/5969aece95b4f1e5)). Use of tag dispatch makes it a bit awkward for the caller, though. – Casey Jun 27 '14 at 17:47
  • @Casey But why `data` can't be `decltype`d ? Here B& data – tower120 Jun 27 '14 at 17:49
  • I think I would stick with a template specialization helper to keep the `if_else(...` syntax. [Maybe this](http://coliru.stacked-crooked.com/a/b7f8973fdb60e778). – Casey Jun 27 '14 at 17:52
  • 1
    @tower120: read the error message, `data` was succesfully `decltype`d. The error message says that you can't pass that `data` to `fn1` because `data` is now a `B&`, and `f1` expects an `A&`. The lambdas will have to have explicit parameter types regardless of the static condition. – Mooing Duck Jun 27 '14 at 17:54
  • 2
    @Casey: If you're making a wrapper for that interface, the backend becomes irrelevent: http://coliru.stacked-crooked.com/a/7216083f7191b980 – Mooing Duck Jun 27 '14 at 17:59

0 Answers0