【问题标题】:Why give a typename template parameter a default value of 0 in C++?为什么在 C++ 中给 typename 模板参数一个默认值 0?
【发布时间】:2016-08-16 18:02:19
【问题描述】:

简短版(如果你像我一样没有耐心,请阅读):

在 C++ 中将 typename 模板参数设置为默认值 0 有什么作用?

我的启用 if 结构:

/**
 * @brief Can be used to enable a template definition using a boolean value
 */
template<lfBool Condition>
struct lfEnableIf
{ };

template<>
struct lfEnableIf<true>
{
   typedef lfInt Type;
};

我的布尔常量结构:

template<lfBool Val>
struct lfBoolConstant
{
    static const lfBool Value = Val;    
};

typedef lfBoolConstant<true> lfTrueType;
typedef lfBoolConstant<false> lfFalseType;

我的类型特征结构(只是其中的一种):

template <typename NumT> struct lfIsArithmetic : lfFalseType{};

template <> struct lfIsArithmetic<lfChar> : lfTrueType{};

最后是我的全部用法:

template<typename T, typename lfEnableIf<lfIsArithmetic<T>::Value>::Type = 0>
struct Test
{
    static void print()
    {
        std::cout << "OK!" << std::endl;
    }

};

int main()
{
    Test<lfFloat>::print();
    Test<lfBool>::print();

    return 0;
}

对不起,我在手机上写这篇文章的格式很差。

长篇(有耐心的请阅读,了解为什么代码不多):

所以,我正在度假,无法使用我的工作站或笔记本电脑,所以我想我会尝试 AIDE,如果你不知道它是一个可以编译 C++ 的 Android IDE。在家里,我正在设计一个包含 Boost 的游戏引擎,我想我会尝试创建类似于 Boost.Core 库中的enable_if 结构的东西。我让它大部分工作但它不会编译,除非我在我启用的模板中将启用 if 结构设置为默认为 0!这就是您使用 Boost enable_ifdisable_if 模板所做的事情。那么在 C++ 中将 typename 模板参数设置为默认值 0 有什么作用呢?

谢谢!

【问题讨论】:

  • 您提供的示例无效。 C++ 中没有这样的功能。适当类型的模板 value 参数将接受默认参数 0,但它不会是 typename 参数。例如。 template &lt;int N = 0&gt; struct S {};.
  • 你不能这样做。默认参数可以是类型,在这种情况下不是数字。
  • 你确定不是&lt;typename SomeType = void&gt;typename boost::enable_if&lt; boost::is_pointer&lt; T &gt;, int &gt;::type = 0之类的东西
  • @AnT 再看一遍我打错了
  • @Zack Frost:current 示例无效。所以还是错了。

标签: c++ templates


【解决方案1】:

这一行

template<typename T, typename lfEnableIf<lfIsArithmetic<T>::Value>::Type = 0>

声明一个命名模板type参数T和一个类型为lfEnableIf&lt;lfIsArithmetic&lt;T&gt;::Value&gt;::Type的无名模板value参数,即第二个参数声明基本上是一个更复杂的版本简单

template <int N = 0> struct S {};

当满足启用条件时,类型lfEnableIf&lt;lfIsArithmetic&lt;T&gt;::Value&gt;::Type解析为类型lfInt,这意味着在这种情况下整个事情等价于

template<typename T, lfInt = 0>

但是,由于第二个模板参数的类型是依赖模板lfEnableIf嵌套 类型,因此您需要使用关键字typename 告诉编译器该成员Type实际上是指一个类型而不是别的东西(即消除歧义)。

同样,模板的第二个参数是无名的,但如果你愿意,你可以给它一个名字。它不会改变任何东西

template<typename T, typename lfEnableIf<lfIsArithmetic<T>::Value>::Type V = 0>

在上面的例子中,我称之为V。该参数的名称不在模板中的任何地方使用,这就是为什么没有真正需要明确指定它的原因。它是一个虚拟参数,这也是它具有虚拟默认值的原因(您可以将 0 替换为 42 - 它也不会改变任何内容)。

在这种情况下,关键字typename 会在模板的两个参数声明之间产生误导性的相似性。实际上,在这些参数声明中,关键字typename 服务于两个非常非常非常不同的不相关目的。

在第一个模板参数声明中 - typename T - 它将T 声明为模板type 参数。在这个角色中,关键字typename可以替换为关键字class

template <class T, ...

在第二个声明中——typename lfEnableIf&lt;lfIsArithmetic&lt;T&gt;::Value&gt;::Type = 0——它有一个次要目的——它只是告诉编译器lfEnableIf&lt;lfIsArithmetic&lt;T&gt;::Value&gt;::Type 是一个类型,从而把整个东西变成一个值 参数声明。在此角色中,关键字 typename 不能替换为关键字 class

【讨论】:

  • 现在我明白了!所以第二个参数可以赋值为零,因为 enable if 模板将“Type”定义为 lfInt,这只是 int 的 typedef。好的谢谢。抱歉花了这么长时间才解决这个问题!
  • 你知道这是否是 SFINAE 安全的吗?即,当您像在template&lt;typename T&gt; Test&lt;T&gt; f(T t) { return { }; } 中一样使用Test 并调用f("hello") 时,它是SFINAE 失败还是严重失败?如果将 enable-if 作为默认模板参数给出,我认为它会失败,因为默认参数实例化被视为自己的定义实例化。但是如果像这样将 SFINAE 埋在参数声明中呢?
  • @Johannes Schaub - litb:是的,你是对的。该技术可用于启用/禁用专业化。尝试在主模板中使用它不会有任何用处。
  • @Johannes Schaub - litb:我预计它会失败,但我不能说我有一个支持性的报价。
  • @AnT 啊有趣,它有效:coliru.stacked-crooked.com/a/765fbf49a1807d11
猜你喜欢
  • 1970-01-01
  • 2012-08-07
  • 2016-04-24
  • 2015-05-09
  • 1970-01-01
  • 1970-01-01
  • 2011-07-15
  • 1970-01-01
  • 2018-07-16
相关资源
最近更新 更多