Search code examples
c++templatesc++11decltype

Decltype with template parameter


Below test1.cpp compiles, but test2.cpp does not. The only difference between the two is that I define Handle::add_it within the class declaration in test1.cpp, but outside in test2.cpp.

test1.cpp: g++ test1.cpp -o test1 -std=c++11

#include <iostream>

template<typename B>
class Handle
{
public:
        decltype(B.operator(int)) add_it(int x)
        {
                return b(x);
        }

        B b;
};

struct Add1
{
        int operator()(int x)
        {
                return x + 1;
        }
};

int main()
{
        Handle<Add1> h;
        std::cout << h.add_it(5) << std::endl;
}

test2.cpp: g++ test2.cpp -o test2 -std=c++11

#include <iostream>

template<typename B>
class Handle
{
public:
        decltype(B.operator(int)) add_it(int x);

        B b;
};

template<typename B>
decltype(B.operator(int)) Handle<B>::add_it(int x)
{
        return b(x);
}

struct Add1
{
        int operator()(int x)
        {
                return x + 1;
        }
};

int main()
{
        Handle<Add1> h;
        std::cout << h.add_it(5) << std::endl;
}

Errors

test2.cpp:13:11: error: expected primary-expression before ‘.’ token
 decltype(B.operator(int))
           ^
test2.cpp:13:20: error: expected type-specifier before ‘(’ token
 decltype(B.operator(int))
                    ^
test2.cpp:13:21: error: expected primary-expression before ‘int’
 decltype(B.operator(int))

Solution

  • You can amend this by using std::declval:

    template<typename B>
    class Handle
    {
    public:
      decltype(std::declval<B>()(int())) add_it(int x) {
        return b(x);
      }
    
      B b;
    };
    

    Live Demo

    Or outside the definition of the class:

    template<typename B>
    class Handle {
    public:
      decltype(std::declval<B>()(int())) add_it(int x);
      B b;
    };
    
    template<typename B>
    decltype(std::declval<B>()(int())) Handle<B>::add_it(int x) {
      return b(x);
    }
    

    Live Demo