Visual C++: cast to function type is illegal, g++ also yields an error

289 views Asked by At

My generated code always used unnecessary many parenthesis simply to make certain, that the C++ code was actually doing what the AST expressed. This is first time I'm getting this compiler error, which I cannot explain -- also before I've used custom types.

(define G_ERROR to get an error...) Visual C++ 2019 yields the following error:

cl -c tmp0.cpp -I ..\Documents\WORK\boost_1_77_0 -DG_ERROR

tmp0.cpp(32): error C2066: cast to function type is illegal
tmp0.cpp(40): error C2675: unary '+': 'abstractValue<32>' does not define this operator or a conversion to a type acceptable to the predefined operator
tmp0.cpp(40): error C2088: '+': illegal for class

g++ v10 yields the following error:

g++-10 -std=c++11 -c tmp0.cpp -I /mnt/c/Users/userName/Documents/WORK/boost_1_77_0/ -DG_ERROR

tmp0.cpp:40:3: error: no match for ‘operator+’ (operand type is ‘abstractValue<>’)
#include <vector>
#include <boost/optional.hpp>

#include <type_traits>
#include <functional>
#include <initializer_list>
#include <set>


struct undetermined
{
};
template<std::size_t SIZE=32>
class abstractValue
{   public:
    abstractValue(const double);
    abstractValue(const undetermined&);

    abstractValue operator+(const abstractValue&) const;
};
struct instance
{
double DTEMP;
abstractValue<> function_231(
        std::vector<boost::optional<abstractValue<>> >&_r
    ) const{
        auto &r = _r.at(231);
        if (
            !r
        )r = 
#ifdef G_ERROR
(
#endif
            abstractValue<>(
                undetermined()
            )
#ifdef G_ERROR
        )
#endif
        +(
            abstractValue<>(
                DTEMP
            )
        );
        return r.value();
        
    }
};
1

There are 1 answers

0
user17732522 On BEST ANSWER
abstractValue<>(undetermined())

Because both abstractValue<> and undetermined are types, there are two interpretations of this without further context:

  1. It is a functional-style explicit cast expression creating a prvalue of type abstractValue<> with (undetermined()) its initializer.

  2. It is a type-id, namely the type of a function returning abstract<> with a single parameter of type "function without parameters returning undetermined" (which is adjusted to "pointer to function without parameters returning undetermined").

You want it to mean the first, not the second. When writing

abstractValue<>(undetermined()) + /*...*/

it cannot have the meaning of 2. and + can only be the binary + operator, but because there are C-style explicit cast expressions in the form of (T)E where T is a type and E an expression, in

(abstractValue<>(undetermined())) + /*...*/

the whole expression could also be such a C-style explicit cast expression with abstractValue<>(undetermined()) being T and +/*...*/ being E with + the unary +.

Because the grammar is ambiguous here, there is a rule saying that any construct that could be interpreted as a type-id in such a situation, is interpreted as a type-id. Therefore the interpretation as 2. is chosen here.

You can avoid this by either simply not using the extra parentheses (as seen they can not always be added without affecting the meaning of an expression) or you can use brace-initialization instead of initialization with parentheses, because braces cannot appear in a function type, disqualifying the 2. immediately in all contexts:

abstractValue<>{undetermined()}

or

abstractValue<>(undetermined{})

or

abstractValue<>{undetermined{}}