Если вы забудете boost::mpl
на секунду, и просто посмотрите на упрощенную форму этого:
eval_if<value_type, A, B>::type::value
Должно быть более ясно, что оба значения A
и B
оцениваются каквторой и третий параметры шаблона, которые должны быть оценены.Так что это не будет ленивым.
Если вы хотите добиться «ленивого» поведения, вы можете использовать специализацию шаблона.
template<bool, class T, class P>
struct has_height_helper {
// `true` case. Evaluate `T::height`
static constexpr bool value = std::is_convertible<decltype(T::height), P>::value;
}
template<class T, class P>
struct has_height_helper<false, T, P> {
static constexpr bool value = false;
}
// And now use the helper in the class
static constexpr bool value = has_height_helper<has_member, T, P>::value;
Поскольку спецификация шаблона в основном «скрывает» код в зависимости от того, чтоиспользуется спецификация.
Другой альтернативой может быть функция constexpr с if constexpr
для скрытия кода:
template<bool has_member, class T, class P>
constexpr bool has_height_helper() {
if constexpr (has_member) {
return std::is_convertible<decltype(T::height), P>::value;
} else {
return false;
}
}
И вы можете просто перенести это в структуру:
template <typename T, typename P = size_t>
struct has_height
{
private:
struct Fallback
{
P height;
};
struct Derived : T, Fallback
{
};
template <class U>
constexpr static bool test(decltype(U::height) *) {
return std::is_convertible<decltype(T::height), P>::value;
}
template <typename U>
constexpr static int test(U *) {
// Basically return any non-bool false so we can tell the difference
return 0;
}
public:
static constexpr bool has_member = std::is_same<test<Derived>(nullptr), bool>::value;
using value_type = std::integral_constant<bool, has_member>;
static constexpr bool value = test<Derived>(nullptr);
};