【问题标题】:Data type of default value for template function argument different from instantiating data type模板函数参数的默认值的数据类型与实例化数据类型不同
【发布时间】:2018-08-28 05:06:24
【问题描述】:
 #include <iostream>
 #include <string>

 template <typename T>
 void f(T x = std::string{""})
 {
   std::cout << '[' << x << ']' << std::endl;
 }

 int main()
 {
   f(23); // Case 1: Doesn't fail
   f<int>(); // Case 2: Compilation error
   f<int>(23); // Case 3: Doesn't fail
 }

Case 1 和Case 3 不应该也失败吗,因为函数模板是由int 实例化的,并且默认值是std::string 类型的。

【问题讨论】:

    标签: c++ c++11 templates language-lawyer default-parameters


    【解决方案1】:

    T x = std::string{""} 仅在没有为 x 提供参数时执行。

    f(23)
    

    隐式实例化为f&lt;int&gt;。未使用 x 的默认值,因为 23 是作为 int 文字提供的。

    f<int>()
    

    现在 T 的类型为 int,但您正在使用 std::string 分配给 x

    f<int>(23)
    

    T 仍然是int,与案例 1 相同

    【讨论】:

    • 好像是这样,但是能不能说明一下这条语句的出处。
    • Default arguments "在函数调用中使用默认参数代替缺少的尾随参数" 所以只有当 x 丢失时才会使用默认参数
    • 您在下面所说的会在默认参数解决后发挥作用。 “如果以需要使用默认参数的方式调用函数模板 f” OP 想知道为什么不使用默认参数将 T 的类型强制为字符串 always。答案是因为默认参数只有在函数调用中用于代替尾随参数时才会发挥作用。因此,您发布的是导致错误的原因,但这并不是为什么 T 始终不是字符串。
    • 没有。你所说的暗示已经有一个功能。但这只是一个函数模板。因此,在这种情况下,实例化具有逻辑优先级。
    【解决方案2】:

    不应该情况 1 和情况 3 也失败,因为函数 模板由 int 实例化,默认值为 type 标准::字符串?

    不,不应该。原因见下文。如果您希望它失败,那么您应该将f() 定义为常规函数,接收std::string 类型的参数并且不是函数模板

    您所拥有的是一个默认参数实例化,请参阅[temp.inst]

    如果函数模板 f 以需要默认值的方式调用 要使用的参数,查找依赖名称,语义 检查约束,并且 实例化 [...] 就像默认参数是 函数模板特化中使用的初始化程序,[...]这个分析是 称为默认参数实例化实例化的默认值 然后将参数用作f的参数

    当你写作时:

    template <typename T>
    void f(T x = std::string{""}){...}
    

    这意味着""x 的默认参数仅在没有任何参数的情况下进行调用。例如在您的案例 2

    您的模板函数被定义为可用于int 或其他各种类型

    例如这里(案例1)

    f(23);
    

    f&lt;int&gt;()隐式设置的(通过基于参数类型的推断),因为 23 在规范中被定义为 int 文字时间>。 int 类型的参数x 接收您在调用站点提供的23非默认值

    这里(案例2)

    f<int>();
    

    正是上面的标准子句发挥作用的地方:您成功实例化f()但没有为其提供任何参数,因此实例化的默认参数然后用作f的参数。因此编译失败,因为这里参数x默认值 被定义为std::string,并且没有从它转换为类型int它实际上等效于在声明为 void f(int x) 的函数上调用 f("")

    这里(案例3)

    f<int>(23);
    

    再次显式,这一次您在调用站点提供正确类型的参数。

    【讨论】:

    • "这仅意味着 std::string 是 f() 的默认参数,以防在没有任何参数的情况下进行调用。"你的意思是在呼叫现场f()
    • @ZeeshanAkhter 完全是朋友。
    • @ZeeshanAkhter 我进行了编辑以使您更清楚。如果还不清楚,请告诉我。
    • 对于f(),您说“它会导致 f<:string>() 的实例化,并且 x 的值将是一个空字符串”,但没有推断出类型参数通过其默认参数,除非您将其设置为类型参数的默认值。仅供参考stackoverflow.com/a/9629009/6367733。所以在这种情况下只写f() 会失败。
    • 我针对 c++17 coliru.stacked-crooked.com/a/30e259f411b8444d 运行了代码,但仍然失败。
    【解决方案3】:

    @Abigail 提供的答案解释了为什么案例 1 和 3 没有失败,让我另外指出函数模板没有那么大的意义。具有一个参数且具有默认值的函数预计可以像这样调用:

    void g(std::string = "") { /* ... */ }
    
    g(); // Use default parameter
    g("non-default");
    

    相比之下,您的函数模板可以使用给定参数调用

    f("non-default");
    

    但不是没有任何参数,因为编译器不会从默认参数推断模板类型。

    f(); // Doesn't compile
    

    我建议将模板更改为

     template <typename T = std::string>
     void f(T x = T{})
     {
         // same as before
     }
    

    修复了f() 实例化。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-09-07
      • 1970-01-01
      • 2020-07-10
      相关资源
      最近更新 更多