【问题标题】:C++ Templates: override some, but not all, default arguments?C++ 模板:覆盖一些但不是全部的默认参数?
【发布时间】:2015-08-05 19:15:02
【问题描述】:

当我遇到一个带有多个默认参数的模板时,例如

template<typename ID = int, typename PAYLOAD = std::string>
class Foo{};

有没有办法让我只覆盖几个默认参数,而不是全部?

即而不是编写以下代码来创建一个使用整数而不是 std::string 作为 PAYLOAD 参数的类,

typedef Foo<int,int> Bar;

我可以写类似的东西吗:

typedef Foo<PAYLOAD=int> Bar;

我正在处理另一个团队的带有许多默认参数的预定义模板,并且能够使用第二种方法似乎可以提高我的代码的清晰度。

查看 StackOverflow 上的文档和其他问题,这似乎是不可能的,但我想知道是否有人可以解释为什么这不是一个功能?

【问题讨论】:

  • Afaik 这仅在 Python 中才有可能(例如,也可能在其他脚本语言中)。在 C++ 中,我没有办法做到这一点。
  • 这些是解决方法,例如boost.parameter,另见stackoverflow.com/q/4209326
  • 您还可以使用一些构建器模式来实现接近于:Foo_builder::Payload&lt;int&gt;::type 的语法,或者指定两个参数 Foo_builder::ID&lt;double&gt;::Payload&lt;int&gt;::type(以任何顺序)。
  • 是所有参数类型吗?按索引覆盖可以吗?

标签: c++ templates default-arguments


【解决方案1】:

在 C++ 的设计和演进中,Bjarne Stroustrup 提到有关于关键字参数的提议;但是,他们被拒绝了,因为

扩展小组达成共识,认为该提案几乎是多余的,会导致与现有 C++ 代码的兼容性问题,并且会鼓励不应鼓励的编程风格。

我想出于同样的原因没有包含关键字模板参数。如果你想简化你的生活,要么typedef 消除复杂性,要​​么编写对模板参数重新排序的适配器类。

【讨论】:

  • 我知道这是委员会的意见,不一定是你的,但你认为你能详细说明为什么这会被认为是“不应该鼓励的编程风格”吗?
  • 当然。在 python 中,看到具有 10 个或更多参数的函数并不少见,其中大多数具有默认值,这些参数可通过关键字参数使用。有这么多的输入是一种不好的代码味道,因为这样的功能难以维护并且不太连贯。对此类函数的建议重构是将相关参数提取到单独的结构中,这些结构提供了创建它们的简单方法。
  • 尽量保持高抽象水平很重要。 bool f(double, double, double, double, double, double, double) 没有告诉你任何事情,bool f(Point&amp;, Point&amp;, double) 开始暗示正在发生的事情:)
  • 对模板参数应用相同的推理。你很少需要超过 3 个——如果你这样做了,你的班级可能做的太多了。但是,如果您有一种简单的方法来使用 10 个参数进行模板化,这将鼓励人们这样做
【解决方案2】:

没有。

不支持这样的模板类型。可以按从左到右的顺序指定类型来代替默认值。

【讨论】:

    【解决方案3】:

    如果模板只伪造类型,则可以用索引替换。

    创建绑定了第一个 n 参数的模板。然后提取参数并替换您想要的参数。

    这要求前 n 个参数在没有位置参数的情况下有效。

    草图:

     template<class...>struct types{using type=types;};
     template<class types, class T, size_t index>
     struct replace{
       using type=/*types with index replaced with `T`*/;
     };
     template<template<class...>class Z,class types>
     struct apply;// applies content of types to Z
     template<size_t n, class T>struct rep{};
     template<class Z, class...reps>
     struct replacing;
     template<template<class...>class Z, class...Ts,class...reps>
     struct replacing<Z<Ts...>,reps...>:
       apply<Z,replacing_t<types<Ts...>,reps...>>
     {};
     template<class...Ts,class T0,class n,class...reps>
     struct replacing<types<Ts...>,rep<n,T0>,reps...>:
       replacing<replace_t<types<Ts...>,T0,n>,reps...>
     {};
     template<class...Ts>
     struct replacing<types<Ts...>>:
       types<Ts...>
     {};
    

    _t 使用别名和一些操作留空。

    那么你可以:

     replacing_t<some_template<>,rep<1,int>>
    

    它使用some_template的默认参数,但将arg1替换为int

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2018-06-21
      • 1970-01-01
      • 1970-01-01
      • 2014-01-21
      • 2012-03-15
      • 2015-05-09
      • 1970-01-01
      • 2014-01-05
      相关资源
      最近更新 更多