首页 > 解决方案 > 短路如何在 std::conjunction 中工作

问题描述

给定以下代码(https://wandbox.org/permlink/Eof3RQs49weJMWan

#include <tuple>
#include <type_traits>
#include <utility>

template <typename T>
inline constexpr auto always_false = false;

template <typename T>
class HardError {
    static_assert(always_false<T>);
};

int main() {
    std::ignore = std::conjunction<std::false_type, HardError<int>>{};
}

我试图理解为什么这不会std::conjunction像上面使用的那样出错。我知道这是为了允许短路,因此不会发生这种情况,这是设计使然。

但是,我不明白允许这种情况发生的语言规则。鉴于以下std::conjunction实施

template<class...> struct conjunction : std::true_type { };
template<class B1> struct conjunction<B1> : B1 { };
template<class B1, class... Bn>
struct conjunction<B1, Bn...> 
    : std::conditional_t<bool(B1::value), conjunction<Bn...>, B1> {};

我们最终继承了这种专业化std::conditional

template<class T, class F>
struct conditional<false, T, F> { typedef F type; };

这需要两种类类型进行实例化。那么conjunction<Bn...>语言是如何省略的呢?

标签: c++templateslanguage-lawyermetaprogramming

解决方案


cppreference(您从中提取该实现的页面)解释了它的工作原理:

连词是短路:如果有一个模板类型参数Bibool(Bi::value) == false那么实例化conjunction<B1, ..., BN>::value不需要实例化Bj::valuefor j > i

具体来说,我们可以看到这一点。您的主要线路:

std::ignore = std::conjunction<std::false_type, HardError<int>>{};

相当于:

std::ignore.operator=(conjunction<std::integral_constant<bool, 0>, HardError<int> >{{}});

这应该会导致实例化,如下所示:

template<>
struct conjunction<std::integral_constant<bool, 0>, HardError<int> > : public std::integral_constant<bool, 0>
{
  inline ~conjunction() noexcept = default;

};

推荐阅读