0

是否有可能以某种方式制作将根据第一个参数接受不同参数的函数(C++11)?可以说,我需要以下行为:

enum TypeFill{Solid, Gradient1, Gradient2};

void fill(const TypeFill t,  Type1 param1 = NULL, Type2 param2 = NULL){
  if (t == Solid){
       fillSolid(param1);
  } else if (t == Gradient1){
       fillGradient1(param1, param2);
  } else if (t == Gradient2){
       fillGradient2(param1, param2);
  }
}

private:
fillSolid(Brush b){};                
fillGradient1(Color c1, Color c2){};
fillGradient2(Color c1, Color c2){};

调用示例:

fill(Solid, Brush(1.0, 0.0, 0.0)){};                
fill(Gradient1, Color(1.0, 0.0, 0.0), Color(1.0, 1.0, 0.0)){};
fill(Gradient2, Color(1.0, 0.0, 0.0), Color(1.0, 1.0, 0.0)){};

只是想知道这是否可能。我觉得这可能与 enable_if 和模板专业化有关,但可能不是......

4

2 回答 2

2

它归结为有几个重载,所以最简单的方法是定义:

  • fillSolid(Brush b)
  • fillGradient(Color c1, Color c2)

在这种设计中,无论如何在每个特定调用中,您都需要在编译时知道枚举值,因此没有太多收获。

OTOH,您可能想要重新设计您的代码,这样您就可以Fill使用不同的实现(例如Solid, Gradient1,Gradient2等)而不是枚举来获得实际的抽象,每个实现都有自己的数据集。


跟进:这是您可以通过模板获得的语法示例:

fill<Solid>::call(Brush(1.0, 0.0, 0.0));               
fill<Gradient1>::call(Color(1.0, 0.0, 0.0), Color(1.0, 1.0, 0.0));
fill<Gradient2>::call(Color(1.0, 0.0, 0.0), Color(1.0, 1.0, 0.0));

枚举器现在是类模板参数,而不是函数参数,因此它在编译时解析,并且(成员)函数签名能够依赖它。

于 2014-01-26T10:38:36.380 回答
0

明智的做法是直接使用您拥有的三个功能。如果您绝对必须具有以下语法:

fill(Solid, Brush(1.0, 0.0, 0.0));
fill(Gradient1, Color(1.0, 0.0, 0.0), Color(1.0, 1.0, 0.0));
fill(Gradient2, Color(1.0, 0.0, 0.0), Color(1.0, 1.0, 0.0));

您可以从两个重载中获取它:

void fill(TypeFill t, Brush b) {
    assert(t == Solid);
    fillSolid(b);
}

void fill(TypeFill t, Color c1,  Color c2) {
  switch(t) {
  case Gradient1:
    fillGradient1(c1, c2);
    break;
  case Gradient2:
    fillGradient2(c1, c2);
    break;
  default:
    assert(false);
    break;
  }
}

如果你非常想要一个函数来抛弃类型安全以及任何调试错误的可能性,你可以使用 C 风格的可变参数:

void fill(TypeFill t, ...) {
  va_list ap;
  va_start(ap, t);
  switch(t) {
  case Gradient1:
    fillGradient1(va_arg(ap, Color), va_arg(ap, Color));
    break;
  case Gradient2:
    fillGradient2(va_arg(ap, Color), va_arg(ap, Color));
    break;
  case Solid:
    fillSolid(va_arg(ap, Brush));
    break;
  default:
    assert(false);
    break;
  }
  va_end(ap);
}

请注意不要违反va_argC++11 §5.2.2/7 中详述的要求:

当给定参数没有参数时,参数以这样一种方式传递,即接收函数可以通过调用va_arg(18.10) 获得参数的值。左值到右值 (4.1)、数组到指针 (4.2) 和函数到指针 (4.3) 标准转换是在参数表达式上执行的。具有(可能是 cv 限定的)类型的参数std::nullptr_t被转换为类型void*(4.10)。在这些转换之后,如果参数没有算术、枚举、指针、指向成员的指针或类类型,则程序是非良构的。传递具有非平凡复制构造函数、非平凡移动构造函数或非平凡析构函数的类类型(第 9 条)的潜在评估参数,没有相应的参数,由实现定义的语义有条件地支持。如果参数具有受整数提升 (4.5) 约束的整数或枚举类型,或受浮点提升 (4.6) 约束的浮点类型,则在调用之前将参数的值转换为提升的类型. 这些提升称为默认参数提升

于 2014-01-26T15:40:13.377 回答