有没有办法避免无意中将非布尔参数传递给布尔参数?

时间:2015-01-29 22:14:27

标签: c++

我今天遇到了C ++类型安全问题,我想知道是否有一种很好的方法可以让编译器在编译时检测到这个问题。请考虑以下示例代码:

class Bar
{
public:
   void Foo(bool arg1 = false, int arg2 = 10, int arg3 = 20)
   {
      [...]
   }
};

int main(int argc, char ** argv)
{
   int x = 40, y = 50;
   Bar b;
   b.Foo();            // correct usage
   b.Foo(true, x, y);  // correct usage
   b.Foo(x, y);        // problem:  compiles but won't do what the caller expects
}

正如对b.Foo()的最后调用所示,问题是很容易忘记提供第一个参数,并且在这种情况下,事情会以一种未被编译器捕获的方式出错。

如果我能让编译器说“ERROR,非布尔值被提供给布尔参数”,那会更好。这将迫使开发人员检查代码,如果他真的想将x作为布尔值传递,他必须传入(x!= 0)而不是。

这似乎是使用“explicit”关键字的好地方,但AFAICT该关键字不适用于函数参数。

(我意识到可以通过不为参数提供默认值来避免这种问题,但默认值可以非常方便)

4 个答案:

答案 0 :(得分:7)

您可以提供已删除的重载:

class Bar
{
public:
   void Foo(bool arg1 = false, int arg2 = 10, int arg3 = 20)
   {
      [...]
   }

    template <typename T>
    void Foo(T&&, int = 10, int = 20) = delete;
};

因为模板方法与非bool参数完全匹配。

答案 1 :(得分:5)

函数重载可以捕获

public: void Foo(bool arg1 = false, int arg2 = 10, int arg3 = 20);

private: void Foo(int&, ...); // can't omit leading arguments, dummy!

或者在C ++ 11及更高版本中,使用= delete(一些所谓的C ++ 11编译器不支持这个),

答案 2 :(得分:4)

正如您所指出的那样explicit bool在此上下文中不起作用 - 但我们可以设法使Explicit<bool>工作,看起来几乎完全相同。

首先,一些SFINAE特质魔法有助于提供一个具有仅适用于真实bool的构造函数的类:

#include <type_traits>
template<typename U>
struct Explicit
{
    bool value;
    template<typename T = U, typename = std::enable_if_t<std::is_same<std::decay_t<T>, U>::value>>
    Explicit(T&& value) : value(value) { }
    operator U() { return value; }
};

有了这个助手,您可以简单地说:

void Foo(Explicit<bool> arg1 = false, int arg2 = 10, int arg3 = 20) { }

请参阅successfailure,并特别注意错误消息:

  

prog.cpp:22:11:错误:无法将'x'从'int'转换为'Explicit&lt; bool&gt;'

答案 3 :(得分:1)

您可以尝试使用模板:

template <class T>
void foo(T param);

template <>
void foo<bool>(bool param)
{

}


foo(true); // OK
foo(9); // Won't c̶o̶m̶p̶i̶l̶e̶  link