给出以下代码(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...>
会如何被语言所取代?
答案 0 :(得分:4)
cppreference(您从中实现的页面)提供了explanation的工作方式:
连接是短路的:如果存在带有
Bi
的模板类型参数bool(Bi::value) == false
,则实例化conjunction<B1, ..., BN>::value
不需要为{{1 }}。
具体来说,我们可以看到这一点。您的主行:
Bj::value
等效于:
j > i
应该引起实例化的东西,如下所示:
std::ignore = std::conjunction<std::false_type, HardError<int>>{};
答案 1 :(得分:2)
模板的实例化不会不触发其模板参数的实例化。参见[temp.inst/2]
这是延迟硬错误的典型方法。
template<class T> struct delay {
using run = T;
};
int main() {
// force instantiation of delay<HardError<int>>,
// but HardError<int> itself is not instantiated
sizeof(delay<HardError<int>>);
delay<HardError<int>> a; // OK, same as above
// Now HardError<int> is instantiated, static_assert failure
// sizeof(delay<HardError<int>>::run);
}
出于相同的原因,std::conditional<false, int, HardError<int>>
的实例化不会导致HardError<int>
的实例化
此外,模板参数甚至不需要完整。
以下代码也有效:
struct incomplete_tag;
int main() { sizeof(delay<incomplete_tag>); }