C++ C+中的Constexpr if then else+;11

C++ C+中的Constexpr if then else+;11,c++,c++11,perfect-forwarding,c++14,c++1y,C++,C++11,Perfect Forwarding,C++14,C++1y,我需要在模板化代码库的某些部分使用constexpr if,但由于它在C++11中不可用,我决定提出我自己的更简单的constexpr if-then-else版本 下面是我对constexpr if-then-else的实现。我不能完全确定它是否正确,也无法在任何地方找到任何适当解释它的相关内容。如果有人能够验证这一点和/或指出替代实现,这将非常有帮助 模板 static_ite(std::false_type,T&&,F&&F){return F;} 模板 constexpr T stati

我需要在模板化代码库的某些部分使用
constexpr if
,但由于它在C++11中不可用,我决定提出我自己的更简单的constexpr if-then-else版本

下面是我对constexpr if-then-else的实现。我不能完全确定它是否正确,也无法在任何地方找到任何适当解释它的相关内容。如果有人能够验证这一点和/或指出替代实现,这将非常有帮助

模板
static_ite(std::false_type,T&&,F&&F){return F;}
模板
constexpr T static_ite(std::true_type,T&&T,F&&){return T;}
模板
constexpr自动静态站点(T&T、F&F)
->decltype(静态_ite(std::integral_常量{},std::forward(t),std::forward(f)))
{
返回静态_ite(std::integral_常量{},std::forward(t),std::forward(f));
}

我打算将其用作通用模板。任何帮助都将不胜感激。

我假设您希望函数返回对您提供的任何内容的引用;如果你想要一份副本,请参考雅克的答案


前两个重载的返回类型应该是右值引用,当您从它们返回时,您应该
std::forward

长的
decltype
可以缩短为
typename std::conditional::type

其他一切对我来说都很好。

template
template <typename T, typename F>
constexpr typename std::decay<F>::type static_ite(std::false_type, T &&, F &&f) { return std::forward<F>(f); }
constexpr typename std::decation::type static_ite(std::false_type,T&&,F&&F){return std::forward(F);}
其他分支也类似。引用可以通过std ref或指针显式传递

我发现更通用的分派也很有用:

template<std::size_t N, class...Ts>
nth_type<N,typename std::decay<Ts>::type...>
dispatch_nth(index_t<N>, Ts&&...ts);
模板
n_型
调度(索引、Ts和…Ts);
(写下明显的助手)

这使您可以处理两个以上的分支


使用
auto
lambda参数器,所有这些都变得异常可怕;尽管如此,它是在大多数早期实现中实现的。

此接口的问题是,您正在评估条件的两侧,因此无论谓词的值如何,两侧都必须有效。因此,更常见的做法是传入lambda,其中一个将在函数中调用。此外,您可能希望传入额外的参数,以便在表达式依赖于类型时,可以确保仅对类型进行有条件的求值(尽管要有效地使用此参数,可能需要C++14泛型lambda)

总之,是这样的:

template <bool cond, typename T, typename F, class... Args>
constexpr auto static_ite(T &&t, F &&f, Args&&... args)
    -> typename std::result_of<typename std::conditional<cond, T, F>::type&&(Args&&...)>::type
{
    return std::forward<typename std::conditional<cond, T, F>::type>(
        std::get<cond ? 0 : 1>(std::make_tuple(std::ref(t), std::ref(f)))(
            std::forward<Args>(args)...);
}
模板
constexpr自动静态站点(T&&T、F&&F、Args&&…Args)
->typename std::result\u of::type
{
返回标准::转发(
std::get(std::make_tuple(std::ref(t),std::ref(f)))(
标准:转发(args);
}

请注意,这使用了
std::tuple
技巧将所有内容放在一个函数体中;如果愿意,您可以使用
std::true\u type
/
std::false\u type
重载方法。

删除了语言律师标签,因为您似乎没有从标准中寻找任何引用。我同意forward,但不同意使用右值引用返回类型;右值引用返回类型只能在非常罕见的情况下使用。@Yakk AdamNevraumont,它会提供OP perfect转发。为什么不呢?因为生命周期问题很容易让人误以为是UB,如果有人需要perfect转发,则可以使用值版本通过冗长的额外代码来实现。@Yakk AdamNevraumont在本例中,右值引用版本是否会导致UB,或者您是否在谈论为什么通常避免返回右值引用?@SauravYadav您的代码本身没有任何UB。要获得UB,您必须将临时对象传递到
static\u ite
,然后将结果分配给引用,这将为您提供悬而未决的参考资料。