Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

No user-defined-conversion operator available that can perform this conversion, or the operator cannot be called

I have a strange error I don't really understand, with VS2013. It's just a simplification of my real problem resulting in the same error.

std::function<bool()> x = (someCondition == true)
    ? []() { return true; }
    : []() { return false; };

VS Compiler error is:

1>f:\test\cppconsoleapplication\cppconsoleapplication.cpp(497): error C2446: ':' : no conversion from 'main::<lambda_96d01fe3721e46e4e8217a69a07d151b>' to 'main::<lambda_0d38919a9b2aba5caf910d83eac11776>'
1>          No user-defined-conversion operator available that can perform this conversion, or the operator cannot be called

IntelliSense even came up with this mysterious error message:

IntelliSense: more than one operator "?" matches these operands:
        built-in operator "expression ? pointer : pointer"
        built-in operator "expression ? pointer : pointer"
        built-in operator "expression ? pointer : pointer"
        built-in operator "expression ? pointer : pointer"
        operand types are: lambda []bool ()->bool : lambda []bool ()->bool  f:\Test\CppConsoleApplication\CppConsoleApplication.cpp 496

whereas the following compiles

std::function<bool()> x = []() { return true; };

if (someCondition == false)
    x = []() { return false; };

Is it just one of VisualStudio's bugs or what am I doing wrong here?

like image 249
Tiresias Avatar asked Jul 08 '16 13:07

Tiresias


People also ask

What do we call user-defined type conversion?

Conversion functions define conversions from a user-defined type to other types. These functions are sometimes referred to as "cast operators" because they, along with conversion constructors, are called when a value is cast to a different type.

What is user-defined conversion in c++?

User-defined conversions allow you to specify object conversions that are implicitly applied by the compiler, in addition to standard built-in type conversions.

What is a conversion operator?

A conversion operator, in C#, is an operator that is used to declare a conversion on a user-defined type so that an object of that type can be converted to or from another user-defined type or basic type. The two different types of user-defined conversions include implicit and explicit conversions.

What is the return type of the conversion operator?

1. What is the return type of the conversion operator? Explanation: Conversion operator doesn't have any return type not even void.


1 Answers

Your code is fine, MSVC is wrong to reject it. According to documentation:

The type and value category of the conditional expression E1 ? E2 : E3 are determined according to the following rules:
[1-4 Don't apply]
5) Otherwise, the result is a prvalue. If E2 and E3 do not have the same type, and either has (possibly cv-qualified) class type, overload resolution is performed using the built-in candidates below to attempt to convert the operands to built-in types. If the overload resolution fails, the program is ill-formed. Otherwise, the selected conversions are applied and the converted operands are used in place of the original operands for step 6.

The aforementioned built-in candidates include a candidate that attempts to convert both operands to a pointer. As both lambdas have an empty capture list, they are convertible to bool(*)(), so this candidate should be chosen. (The other candidates do not fit, so the pointer one is not ambiguous.)

To summarize:

(someCondition == true)
    ? []() { return true; }
    : []() { return false; };

should convert both lambdas to bool(*)() and yield a pointer-to-function that, when invoked, has the same effect as the selected lambda. This pointer is not dangling, independent of the lifetime of the lambda objects. (Details here.)
The resulting function pointer can then be assigned to the std::function.

Note that both lambdas having an empty capture list is vital. If one of the lambdas would capture something, the conversion to pointer would not work anymore and the code would be ill-formed.

You can probably help your old MSVC by explicitly casting one or both lambdas to bool(*)() or std::function<bool()>. The latter would also allow you to use lambdas with a non-empty capture list. (Live)


To explain the diagnostics your IDE gives you:

The compiler error seems to stem from step 3) from the list I linked: It tries to convert one operand to the type of the other one and fails.

IntelliSense seems to have the right idea at least and complains about the overload resolution as described in step 5). Why it finds too many candidates I don't know. This is a bug.

like image 67
Baum mit Augen Avatar answered Sep 22 '22 00:09

Baum mit Augen