I have a templated function, and at one point I would like to have different code depending on the template parameter:
template <typename T>
void function(const T ¶m) {
    // generic code here...
    // pseudo-code:
    if constexpr isinstance(param, Banana) {
        param.peel();
    } else if constexpr isinstance(param, Apple) {
        // do nothing, Apple has no method `peel`
    }
}
I don't want to specialize the whole function, since most of the code is shared. The statement I want to insert is acutally a temporary debugging measure. I know the correct thing would be to create a overloaded function doPeel and call that instead:
void doPeel(const Banana ¶m) { param.peel(); }
void doPeel(const Apple ¶m) {}
But I'm curious, is there a way to tell at compile time, in a function, what (template specialization) type a given variable is... in order to use statements that only compile for one type?
I wonder if something like that is possible with constexpr - or does the compiler enforce types in a discarded branch? I also tried making up something with lambdas - defining lambdas for both cases and only calling one, but I could not find a way to do it. Any ideas?
There is if constexpr in C++17:
template<typename T>
void foo(T const& t)
{
    if constexpr(is_same<decay_t<T>, int>::value) {
        cout << __PRETTY_FUNCTION__ << " " << t * 2 << endl;
    } else {
        cout << __PRETTY_FUNCTION__ << endl;
    }
}
live demo
In C++14 you could hack something like this:
template<typename T>
void foo(T const& t)
{
    conditional_eval<is_same<decay_t<T>, int>>([=](auto){
        cout << __PRETTY_FUNCTION__ << " " << t * 2 << endl;
    },[](auto){
        cout << __PRETTY_FUNCTION__ << endl;
    });
}
With conditional_eval defined as:
template<typename IfTrue, typename IfFalse>
void conditional_eval_impl(std::true_type, IfTrue&& t, IfFalse&&) {
    t(0);
}
template<typename IfTrue, typename IfFalse>
void conditional_eval_impl(std::false_type, IfTrue&&, IfFalse&& f) {
    f(0);
}
template<typename Tag, typename IfTrue, typename IfFalse>
void conditional_eval(IfTrue&& t, IfFalse&& f) {
    conditional_eval_impl(Tag{}, std::forward<IfTrue>(t), std::forward<IfFalse>(f));
}
live demo
In C++14 you could emulate if constexpr using generic lambda e.g. by:
#include <type_traits>
#include <iostream>
template <bool B>
struct constexpr_if {
   template <class Lambda, class T>
   static void then(Lambda l, T&& value) { }
};
template <>
struct constexpr_if<true> {
   template <class Lambda, class T>
   static void then(Lambda l, T&& value) {
      l(std::forward<T>(value));
   }
};
struct Banana {
   void peel() const {
     std::cout << "Banana::peel" << std::endl;
   }
};
struct Apple {
};
template <typename T>
void function(const T ¶m) {
    constexpr_if<std::is_same<T, Banana>::value>::then([&](auto &p){
       p.peel();
    }, param);
}
int main() {
  function(Banana{});
  function(Apple{});
}
                        If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With