C ++ 11函数参数

时间:2014-01-26 10:30:59

标签: c++ templates c++11 sfinae enable-if

是否有可能以某种方式使函数(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和模板特化有关,但可能不是......

2 个答案:

答案 0 :(得分:2)

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

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

在这个设计中,你需要在每个特定的调用中在编译时知道枚举值,所以没有太大的收获。

OTOH你可能想重新设计你的代码,这样你就可以使用FillSolid,{{Gradient1Gradient2来实现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)); 的实际抽象,而不是枚举。 1}}等,每个都有自己的数据集。


后续行动:这是您可以通过模板获得的语法示例:

{{1}}

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

答案 1 :(得分: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_arg要求,详见C ++11§5.2.2/ 7:

  

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