C++ 在使用“std::enable_if”时,如何避免写入“::value”和“::type”?[cppx]

C++ 在使用“std::enable_if”时,如何避免写入“::value”和“::type”?[cppx],c++,templates,c++11,C++,Templates,C++11,注意:这是一个,目的是记录其他人可能会发现有用的技术,并了解其他人更好的解决方案。请随意添加评论或问题作为评论。也可以随意添加其他答案。:) 在我的一些代码中,即标题rfc/cppx/text/String.h,我发现了以下神秘片段: template< class S, class enable = CPPX_IF_( Is_a_< String, S > ) > void operator! ( S const& ) { string_detail::Me

注意:这是一个,目的是记录其他人可能会发现有用的技术,并了解其他人更好的解决方案。请随意添加评论或问题作为评论。也可以随意添加其他答案。:)
在我的一些代码中,即标题
rfc/cppx/text/String.h
,我发现了以下神秘片段:

template< class S, class enable = CPPX_IF_( Is_a_< String, S > ) >
void operator!  ( S const& )
{ string_detail::Meaningless::operation(); }
这看起来像是
std::enable_if

template< class S, class enabled = typename std::enable_if< Is_a_< String, S >::value, void >::type >
void operator!  ( S const& )
{ string_detail::Meaningless::operation(); }
template::value,void>::type>
无效操作员!(S常数&)
{string_detail::无意义::operation();}
除了
If
CPPX\u If
及其表达式更简洁易读之外


我到底是怎么做到的?

使用编译器的舒适的C++11-
功能就是

namespace cppx {
    using std::enable_if;

    template< class Condition_type, class Result_type = void >
    using If_ = typename enable_if<Condition_type::value, Result_type>::type;

}  // namespace cppx
这基本上只提供了一个更可读的名称,并且在条件中省去了
::value
。为了省去
typename
::type
我使用了一个宏。但由于表达式通常是模板表达式,因此预处理器可能会将逗号解释为参数分隔符,以便预处理器可以看到多个参数

namespace cppx {
    using std::integral_constant;

    template< bool c >
    using Bool_ = integral_constant<bool, c>;

    using False = Bool_<false>;     // std::false_type;
    using True  = Bool_<true>;      // std::true_type;

    template< bool v, class First, class... Rest >
    struct Count_
    {
        enum{ value = Count_<v, First>::value + Count_<v, Rest...>::value };
    };

    template< bool v, class X >
    struct Count_<v, X>
    {
        enum{ value = int(!!X::value == v) };
    };

    template< class X >
    using Not_ = Bool_<Count_<true, X>::value == 0>;                   // NOT

    template< class... Args >
    using All_ = Bool_<Count_<false, Args...>::value == 0>;            // AND

    template< class... Args >
    using Some_ = Bool_<Count_<true, Args...>::value != 0>;     // General inclusive OR.

    template< class... Args >
    using Either_ = Bool_<Count_<true, Args...>::value == 1>;   // General exclusive OR.
}  // namespace cppx
我使用的解决方案(C++03的时代对我来说已经结束)是使用C99/C++11可变宏

#define CPPX_IF_( ... ) \
    typename cppx::If_T_< __VA_ARGS__ >::T
此外,为了完整性,
是一个
被简单地定义为

template< class Base, class Derived_or_eq >
using Is_a_ = std::is_base_of<Base, Derived_or_eq>;

免责声明:没有一个代码被广泛测试,C++模板编译器在模板元编程领域的奇特是常见的。

< P> C++ 14中,变量模板使类型特征更容易观察。再加上C++11模板别名,所有的污点都会消失:

template <typename A, typename B>
bool is_base_of_v = std::is_base_of<A, B>::value;

template <bool B, typename T = void>
using enable_if_t = typename std::enable_if<B, T>::type;
模板
bool是v=std::的基础值::value的基础值;
模板
使用enable_if_t=typename std::enable_if::type;
用法:

template <typename B, typename D>
enable_if_t<is_base_of_v<B, D>, Foo> some_function(B & b, D & d) { /* ... */ }
模板
启用某些函数(B&B,D&D){/*…*/}

“Type”形式的别名实际上是C++14标准库的一部分,请参见[meta.Type.synop]。

我们有C++03、C++11和C++14解决方案,但缺少:

template <typename Derived, typename Base>
constexpr bool Is_a_() {
  return std::is_base_of<Base, Derived>::value;
}

template<Is_a_<String> S>
void operator! ( S const& )
{ string_detail::Meaningless::operation(); }
模板
constexpr bool是{
return std::是::value的_base_;
}
模板
无效操作员!(S常数&)
{string_detail::无意义::operation();}
或者更简洁地说:

template <typename Derived, typename Base>
concept bool Is_a_() {
  return std::is_base_of<Base, Derived>::value;
}

void operator! ( Is_a_<String> const& )
{ string_detail::Meaningless::operation(); }
模板
概念布尔是{
return std::是::value的_base_;
}
无效操作员!(是常数&)
{string_detail::无意义::operation();}

我强烈建议浏览本文的教程(第2节),了解一下在我们摆脱了
enable\u if
霸主之后,世界会变得多么美好。

std::enable\u if\u t
这样的新模板别名是C++14的一部分,我相信。@KerrekSB,酷,我不知道他们真的实施了这些。你知道他们有没有为
::value
做过任何
\u v
变量模板或其他什么吗?@KerrekSB:谢谢!我不知道。它省去了
typename
::type
字眼,但没有
::value
。总之,Visual C++还没有支持。可能不会很长时间……取消
::value
需要可变模板。这些也是C++14的一部分,但我不知道是否计划了相应的新特性。看起来不像,尽管那是一种耻辱,等等。如
模板bool是\u base\u of of v=std::is\u base\u of::value
。你可以用C++14编写。这比你的特殊条件评估包装更干净。很高兴知道,谢谢!但是,在软膏中,一个在Windows中实际上无法使用它,直到VisualC++支持它…@ TeMtPrimeX:是的,C++和111模板别名都用于MIGER和Kerrek的答案,但是,不,VC 12支持不完整,也不完全是无bug的。对于即将到来的C++ 14“变量模板”,上面的代码没有用Visual C++ 12(2013)编译。它也不是用g++4.8.2编译的。因此,我认为这与我对So(一个大约有50%的类似Herb Schildt的虚假信息的网站,可能是网络上最大的此类信息)的看法是一致的,你的评论被两位读者投了更高的票。C++14信息+1(在你发布这篇文章时是正确的)。然而,它只是事物的形状。@ TePrimeRe: RE“你能给出一个小例子,这个特性在VC++上不起作用”,如上面提到的两次(这个答案)是一个不工作的例子,不支持,如VisualC++ 2013。但是我不能预测未来,抱歉。啊,我刚刚检查过,N3797确实指定了一个
std::enable\u if\t
。我将提交一个DR.Concepts Lite,它还具有闪亮和新颖的优点,因此微软可能会在修复C++98错误之前在他们的编译器中实现它。
template <typename B, typename D>
enable_if_t<is_base_of_v<B, D>, Foo> some_function(B & b, D & d) { /* ... */ }
template <typename Derived, typename Base>
constexpr bool Is_a_() {
  return std::is_base_of<Base, Derived>::value;
}

template<Is_a_<String> S>
void operator! ( S const& )
{ string_detail::Meaningless::operation(); }
template <typename Derived, typename Base>
concept bool Is_a_() {
  return std::is_base_of<Base, Derived>::value;
}

void operator! ( Is_a_<String> const& )
{ string_detail::Meaningless::operation(); }