Prevent silent cast from false to pointer

2019-06-18 04:27发布

I have a function

void foo(int *bar)
{}

Visual Studio 2012 will now happily and without warnings compile if I call foo like this:

int main()
{
  foo(false);
  return 0;
}

If I however change foo(false) to foo(true) than I get an error:

1>main.cpp(132): error C2664: 'foo' : cannot convert parameter 1 from 'bool' to 'int *'
1>          Conversion from integral type to pointer type requires reinterpret_cast, C-style cast or function-style cast

Any idea how I can make sure that I get an error when passing false, too? My only idea is to add a second private function "void foo(bool bar)". Then I indeed get the desired error stating that foo(bool bar) is private. But this only works when foo is called from outside the class and it clutters my interface.

3条回答
Melony?
2楼-- · 2019-06-18 04:51

In C++11, you may write:

void foo(bool) = delete; // cannot be use by anybody (class itself included).

As vs2012 doesn't support = delete,

You may try this hack using SFINAE:

template <typename T>
typename std::enable_if<std::is_same<T, int>::value, void>::type
foo(T* t);

With the old C++98 way 'private without implementation':

private:            // Fail to compile from outside
    void foo(bool); // No implementation -> fail to link time if internally used.
查看更多
太酷不给撩
3楼-- · 2019-06-18 04:56

First, as to why it accepts false but not true: The literal false will be interpreted as the integral 0 and a literal 0 will convert to a null pointer of any type. true on the other hand cannot be converted to a pointer type as it converts to an integral 1.

As to how to solve your problem: Your approach with an extra bool overload will work fine for both public and non-public callers as long as you don't implement the private overload. In that case public callers will get a compile error and member callers will get a linker error.

However, you may wish to consider additional things as well.

Does your function need to accept null pointers? If not, change it to accept by reference instead and the problem just goes away.

If your function really does need to accept null pointers then I would suggest in this case to just trust your users to call it correctly instead of cluttering your interface trying to prevent every possible misuse.

查看更多
ゆ 、 Hurt°
4楼-- · 2019-06-18 05:02

You can wait for C++17, when Concepts can be used anywhere auto is in C++11, and write your signature as:

void foo( IsActually<int*>::template test x ) { }

... which actually looks pretty bad, but they may clean up the syntax by then.

查看更多
登录 后发表回答