Is there a way to avoid unintentionally passing a non-boolean argument to a boolean parameter?

Today I have a security issue such as C ++, and I am wondering if there is a good way to get the compiler to detect this problem at compile time. Consider this code example:

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 } 

As shown in the last call to b.Foo (), the problem is that it is easy to forget to provide the first argument, in which case everything goes wrong as it is not caught by the compiler.

Which would be nice if I could get the compiler to say something like "ERROR, a non-Boolean value was passed to a boolean parameter". This would force the developer to learn the code, and if he really wanted to pass x as a logical one, he would have to go (x! = 0) instead.

This seems like a good place to use the "explicit" keyword, but AFAICT this keyword does not work for function arguments.

(I understand that this kind of problem could be avoided by not supplying default values ​​for the arguments, but the default values ​​can be quite useful)

+7
c ++
source share
4 answers

The overload function may catch that

 public: void Foo(bool arg1 = false, int arg2 = 10, int arg3 = 20); private: void Foo(int&, ...); // can't omit leading arguments, dummy! 

Or in C ++ 11 and later use = delete (some so-called C ++ 11 compilers do not yet support this)

+5
source share

You can provide remote overloads:

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

Since the template method will be an exact match for the non bool parameter.

+7
source share

As you noted, explicit bool does not work in this context, but we can instead do Explicit<bool> , which looks pretty accurate.

Firstly, a little SFINAE trait magic helps to create a class that has a constructor that works only for real bool s:

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

With this helper, you can simply say:

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

See success and failure and pay special attention to the error message:

prog.cpp: 22: 11: error: failed to convert 'x' from 'int' to 'Explicit <bool>'

+4
source share

You can try using this trick with a template:

 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 
+1
source share

All Articles