分支函数中的模板参数

Branch on a template parameter in function?

本文关键字:参数 函数 分支      更新时间:2023-10-16

我有一个模板化的函数,在某一点上,我希望根据模板参数有不同的代码:

template <typename T>
void function(const T &param) {
    // 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`
    }
}

我不想专门化整个函数,因为大部分代码是共享的。我要插入的语句实际上是一个临时调试措施。我知道正确的做法是创建一个重载函数doPeel并调用它:

void doPeel(const Banana &param) { param.peel(); }
void doPeel(const Apple &param) {}

但我很好奇,有没有一种方法告诉在编译时,在一个函数中,什么(模板专门化)类型给定变量是…为了使用语句,只编译一种类型?

我想知道这样的事情是否可能与constexpr -或者编译器强制类型在丢弃的分支?我也试着用lambda来做点什么——为这两种情况定义lambda并且只调用一个,但是我找不到一个方法来做。什么好主意吗?

c++ 17中有if constexpr:

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

现场演示


在c++ 14中,你可以这样修改:

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

conditional_eval定义为:

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

现场演示

在c++ 14中,您可以使用泛型lambda来模拟if constexpr,例如:

#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 &param) {
    constexpr_if<std::is_same<T, Banana>::value>::then([&](auto &p){
       p.peel();
    }, param);
}
int main() {
  function(Banana{});
  function(Apple{});
}