2014-01-26 38 views
0

是否有可能以某种方式使函数(C++ 11),它将接受不同的参数取决于第一个? 比方说,我需要以下行为: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

什么是'枚举TypeFill ;'?...和其他代码中,我不知道你想要达到什么目的。 – Nawaz

+0

因为在编译时需要知道填充类型,所以像这样比'solidFill(Brush)','gradientFill(Color,Color)'等更好吗?当然,有很多方法可以公开这样的API;我只是选择最明显的简单案例作为参考。 – Jon

+0

@Nawaz:他们想根据第一个参数的值(这是不可能的,因此我们正在谈论一些道德等价物)允许或不允许“fill”的不同签名。 – Jon

回答

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); 
} 

要小心,不要落入相抵触的详情见C++ 11§5.2.2/ 7 va_arg要求:

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

2

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

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

在本设计中你需要枚举值在编译时反正在每个特定的呼叫是已知的,所以没有太多的收获。

OTOH你可能会想重新设计你的代码,这样,而不是一个枚举你有Fill有不同的实现实际的抽象像SolidGradient1Gradient2,等等,每一个都有自己的数据集。


后续:这是一个语法的例子,你可以使用模板得到:

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

提示:唯一的事情模板可以做的是代码生成,而且你首先需要一个想法,真的很有趣的代码生成 – Kos

+0

。 – tower120

+0

@Kos虽然技术上是的,但我不同意你的'唯一'部分。这里期望的行为实际上可以用简单的模板专门化来实现,尽管我不认为这适合于此。 – Paranaix