Question

I'm using coliru.

Command line is:

g++ -std=c++11 -O2 main.cpp && ./a.out
clang++ -std=c++11 -O2 main.cpp && ./a.out

The following code compiles fine in g++ but not in clang++.

    template <typename T, typename... U>
    A& operator ()(T a, U... b)
    {
        struct Inner { 
            operator decltype(T(U...)) const {
                return a(b...);
            }
        } inner;

        return *this;
    }

main.cpp:17:37: error: 'U' does not refer to a value

            operator decltype(T(U...)) const {

                                ^

main.cpp:13:43: note: declared here

    template <typename T, typename... U>

                                      ^

1 error generated.

The error I get now is:

main.cpp:18:41: error: reference to local variable 'a' declared in enclosing function 'operator()'

My class looks like this:

template <typename R>
class A {
        R value = R();
    public:
        A() { }
        ~A() { }
        template <typename T, typename... U>
        A& operator ()(T a, U... b)
        {
            struct Inner { 
                operator decltype(std::declval<T>()(std::declval<U>()...))() const {
                    // some code here to return a(b...)
                }
            } inner;
            value += inner;
            return *this;
        }

        R val() {
            return value;
        }
};
Was it helpful?

Solution

The compiler is right, it refers to types, not values. You need to write:

operator decltype(std::declval<T>()(std::declval<U>()...))() const {
// you need       ^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^ and ^^
    return a(b...);
}    

(the last () are needed to make it a valid conversion operator of the form operator T() const)

That said, you can not use a and b... inside of Inner, so the whole example doesn't make any sense. Whatever your use-case is, the above doesn't really work, I can just show you how to fix the signature so that Clang accepts the code, but you will still be unable to use it.


And after your update, it's an entirely different question now. Maybe this works for you:

template <typename R>
class A {
    R value = R();
public:
    A() { }
    ~A() { }
    template <typename T, typename... U>
    A& operator ()(T a, U... b)
    {
        struct Inner { 
            using R2 = decltype(std::declval<T>()(std::declval<U>()...));
            R2 impl(T a, U... b) const {
                return a(b...);
            }
        } inner;
        value += inner.impl(a,b...);
        return *this;
    }

    R val() {
        return value;
    }
};

Referring to Walter's comment: You could, now that you pass the parameters, also use trailing return types:

struct Inner { 
    auto impl(T a, U... b) const -> decltype(a(b...)) {
        return a(b...);
    }
} inner;

or with C++14, you could use

struct Inner { 
    auto impl(T a, U... b) const {
        return a(b...);
    }
} inner;
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top