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.
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.
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.
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.
Related
Can anybody tell me if there is a way to force a compilation error when a const wchar_t* function argument gets passed a 0 pointer?
As example:
void func(const wchar_t* a)
{
...
}
int main()
{
...
func(0); // <- this should generate a compilation error
...
}
My intention here is not to skip any validation checks inside the function for this argument but rather prevent compilation if a function call simply makes no sense at all.
I am using Visual Studio 2019
Thanks!!
UPDATE
I tried to add an overload for std::nullptr_t as mentioned by #Jarod42
This generates a compilation error, but the error it produces is
"more than one instance of overloaded function matches the argument list"
although it prevents compilation, the error itself is kind of missleading and doesn't address the real problem
adding an overload with the parameter replaced by int type also get a missleading compilation error
"tried to acces a deleted function"
and yes, sadly none of those prevent a call with (const wchar_t*)0 argument
so, i would say that i want to reject the 0 literal as well as the (const wchar_t*)0argument
You might add overload for std::nullptr_t:
void func(std::nullptr_t) = delete;
Or maybe a catch all one:
template <typename T> void func(T) = delete;
Let's say we have got a raw C-style string "test". We can declare a function like this:
void printText(std::string textToPrint){
std::cout << textToPrint << "\n";
}
and we may call it in a following manner:
printText("test");
And this should be perfectly fine, as argument is an object, not a reference, so temporary object like std::string("test") should be created in time of calling function `printText()'.
Now given that, I have a following template:
template <typename T>
T checkMe(Proxy<T> arg){
std::cout << arg() << std::endl;
return arg();
}
where Proxy class declaration is as follows:
template <typename T>
class Proxy{
public:
Proxy(std::function<T&()> caller);
Proxy(std::shared_ptr<T> dataPtr);
T& operator()();
private:
std::function<T&()> m_functional;
std::shared_ptr<T> m_data;
};
It's purpose is to make some of the functions be called with two object types:
One is shared_ptr to the data and another is functional object, that returns this type of data.
Now when I want to call function checkMe error happens, that I do not know why appears and how to solve it. One thing is:
getMe(std::make_shared<int>(255));
And this in my opinion should be perfectly fine, as Proxy's constructor takes shared_ptr as argument and creates itself based on it. But this gives compiler's deduction error. Whereas, when I call function like this:
getMe<int>(std::make_shared<int>(255));
Well now it's fine. I do not know why does compiler cannot deduce the type on it's own.
Second case is calling it with a functional object:
getMe<int>(std::bind(getNumberMult,5,6));
Where getNumberMult is defined as follows:
int xy;
int& getNumberMult(int x, int y){
return xy = x*y;
}
Here conversion error occurs. Could someone please specify is it possible and how to achieve desired behavior of the given code and explain what is wrong with my understanding of the mechanism? I would like to use this code as follows:
getMe(std::make_shared<int>(300));
getMe(std::bind(getNumberMult, 6, 7));
Compiler errors:
when using
getMe<int>(std::bind(getNumberMult, 5, 6));
path/to/file:36: error: C2664: 'T getMe<int>(DataProxy<T>)' : cannot convert argument 1 from 'std::_Bind<true,int &,int &(__cdecl *const )(int,int),int,int>' to 'DataProxy<int>'
with
[
T=int
]
With T checkMe(Proxy<T> arg), arg should be a Proxy<T> (or inherit from it).
Compiler doesn't check the infinite possibilities to test each Proxy<T> can be construct from given argument.
So generally I know now why it is so, and what should I do to fix it.
Consider following object:
struct Test{
Test(std::string someString){}
};
So we need std::string just for constructing object of this class.
We can do without std::string created explicitly in following manner:
int main(){
Test someVariable("someRawString");
}
It's gonna work and it is completely fine. What happens underhood is:
compiler meets instruction for creating object of Test class
It sees, that given argument is not of type required by Constructor
because of the fact, that required argument is a value, not a reference (const reference would also be fine) it creates temporary object of type std::string and passes this temporary object to the constructor
Object is successfully created.
Now let's consider function:
void someTestFunction(Test someTest){}
It requires object of type Test, that is constructed from std::string
Given that, it should be fine to invoke this function in following manner:
someTestFunction("someRawText");
But it's not fine. This gives us error of converting arguments. Reason for it is quite simple: C++ allows only one step of converting, when passing parameters to the function. So compiler can:
cast raw string to std::string
create Test object with std::string
But it cannot:
cast raw string to std::string
cast std::string to Test (too many conversions)
invoke function with Test
Exactly the same things happened with the given code. To make it work we should use:
getMe<int>(std::make_shared<int>(300));
getMe<int>(std::function<int&()>(std::bind(getNumberMult, 6, 7)));
Why is it so?
std::make_shared<int> has return type of std::shared_ptr<int>, so no conversion was required to invoke a function.
std::bind... has a returning type different than std::function, it has it's own implementation defined return type. That is why this second cast would be required here, which is not allowed by C++. When we cast it explicitly, then only one implicit cast is required and everything works fine.
Consider the code:
void fnc(int, long, double*){}
template<int I> void f(int, long, double*){}
int main()
{
bool a = fnc; //(1) ok
bool b = f<4>; //(2) error
}
It triggers an error:
error: cannot resolve overloaded function 'f' based on conversion to type 'bool'
bool b = f<4> //(2) error
Why first case is correct, but second case isn't correct?
You are totally neglecting all the warnings, which are there to tell you that you're doing something very wrong.
Besides, you should use the & to get the function address.
Secondly, you're implicitly casting a function pointer to a bool variable.
Cast it explicitly to tell the compiler that you think you know what you're doing and you're sure about it:
bool b= (void*)&ff<4>;
I just have to say that casting stuff to avoid errors and warning is a bad idea.
In most cases the warnings and errors are there to help you avoid loss of data and things that usually do cause runtime errors.
Suppose I have a function that performs some side effect and then returns an answer:
int foo()
{
perform_some_side_effect();
return 42;
}
I want to bind foo to a function pointer, but I'm not interested in the answer, just the side effect:
void (*bar)() = foo;
However, this appears to be a type error:
error: invalid conversion from ‘int (*)()’ to ‘void (*)()’
What is the rationale behind that error? Why doesn't the type system allow me to ignore the answer?
On a side note, it works if I wrap the function pointer in a std::function:
std::function<void()> baz = foo;
How does std::function (apparently) manage to circumvent this restriction in the type system?
What is the rationale behind that error? Why doesn't the type system allow me to ignore the answer?
The reason is that the types are different, and the generated code at the place of call (through the function pointer) is different. Consider a calling convention where all arguments are written to the stack and space for the return value is also reserved in the stack. If the call goes through a void (*)() then no space will be reserved in the stack for the return value, but the function (unaware of how it is being called) will still write the 42 to the location where the caller should have reserved space.
How does std::function (apparently) manage to circumvent this restriction in the type system?
It does not. It creates a function object that wraps the call to the actual function. It will contain a member like:
void operator()() const {
foo();
}
Now when the compiler processes the call to foo it knows what it has to do to call a function that returns an int and it will do so according to the calling convention. Because the template does not return, it will just ignore the value --that was actually returned.
std::function need only be source compatible- that is, it can generate a new class which generates new caling code that ignores the result. The function pointer must be binary compatible and cannot do that job- void(*)() and int(*)() point to the exact same code.
You can think of std::function<> doing this for your particular case:
void __func_void()
{
foo();
}
It's actually a bit more complicated than that, but the point is that it generates template code together with type-erasure to not care about the specifics.
In addition to what others have been saying, the caller also need the return type to know what destructor it should invoke on the result (the return value may be a temporary).
Unfortunately it is not as easy as
auto (*bar)() = foo;
Although GCC and Clang accept this. I need to recheck the spec to see whether that's actually correct.
Update: The spec says
The auto type-specifier signifies that the type of a variable being declared shall be deduced from its initializer or that a function declarator shall include a trailing-return-type.
This can be misleading when read fast, but this is implemented by GCC and clang to only apply to the toplevel declarator. In our case, this is a pointer declarator. The declarator nested in it is a function declarator. So just substitute auto for void and then the compiler will deduce the type for you.
By the way, you can always make this work manually, but it takes some trickery to make it work
template<typename FunctionType>
struct Params;
template<typename ...Params>
struct Params<void(Params...)> {
template<typename T>
using Identity = T;
template<typename R>
static Identity<R(Params...)> *get(R f(Params...)) {
return f;
}
};
// now it's easy
auto bar = Params<void()>::get(foo);
I have:
int foo(int x) { return x+1; }
struct Bar {
decltype(foo) operator();
};
int main() {
Bar bar;
printf("%d\n",bar(6));
}
which results in the slightly startling compiler error message (g++ 4.6.1):
error: declaration of 'operator()' as non-function
When changing the member name to
decltype(foo) blubb;
and using it results in a linker error:
undefined reference to `Bar::blubb(int)'
Is this expected behaviour?
It seems that you want to "copy" the signature of another function to create a function with the same signature. Since decltype(foo) is indeed the type of the function (and not a pointer to that function, which would be decltype(&foo) and would lead to a pointer declaration), you can use it to declare a function with the same signature as another function.
As indicated by the linker error:
undefined reference to `Bar::blubb(int)'
this will already work fine with your compiler. However it seems that gcc did not yet fully implement this part of the standard, as it will not accept the syntax for the same thing with a function call operator. Clang btw. will happily accept it and the link then errors out with
undefined reference to `Bar::operator()(int)'
Your question about why that linker error exists indicates a misunderstanding of what decltype really does.
It will just evaluate to a type, not more. The definition of blubb is in no way tied to the definition of foo. This might be clearer when writing it like
typedef decltype(foo) x;
x blubb;
You can now alternatively typedef x to be explicitly the function type, which will not in any way change what blubb is. You still need to define it. And since there is no syntax to define it using decltype, you explicitly have to write it as
int Bar::operator()(int) {
...
}
which will likely and unfortunately defeat the purpose/benefit of using decltype for the declaration, as it will not allow you to automatically "copy" a signature.
This is a wild guess based on observing your usage of printf here:
printf("%d\n",bar(6));
This lets me assume you really want the return type of the function, not the type of the function. If so, then you use decltype wrong. You get the return type of the function by "simulating" the usage of the function, i.e.
decltype(foo(0)) operator() (int);
should be the right thing for you. Otherwise, if that was not your attention, you are skating on thin ice by giving a function type (and not function return type) to the %d specifier.
Generally, the meaning of decltype is: decltype(#) gives the static type of the expression #.
This should work.
I just used it here to capture whatever gobbledygook std::bind was going to give me:
class RiceFadingModel::Impl
{
public:
Impl(double K, double A)
: //...
_M_re{system_now()},
_M_rd{_M_nu, _M_sigma},
_M_gen{std::bind(_M_rd, _M_re)}
{ }
private:
//...
std::default_random_engine _M_re;
/// The underlying Rice distribution.
__gnu_cxx::__rice_distribution<double> _M_rd;
/// The variate generator built from the pseudo-random number engine and the Rice distribution.
decltype(std::bind(_M_rd, _M_re)) _M_gen;
};
This works like a charm on gcc-4.7. Now that I think about it I built it on mingw with gcc-4.5 too.