Heisenbug
Heisenbug

Reputation: 39174

deduced return type depedent on member function template argument

I am trying to figure out what's wrong with this code:

#include <string>

struct Bar
{
    using Deduced = typename std::string;
};

class Test
{
    template<typename Foo>
    auto Func() ->  decltype(Foo::Deduced)
    {
        return Foo::Deduced();
    }
};

int main()
{
    Test t;
    std::string ret = t.template Func<Bar>();
}

I am refactoring a class where Func return type was declared as a template class parameter of Test class, but I would like to change this to work as a member template parameter.

Is this possible? If yes, anyone could suggest me the right syntax?

Upvotes: 1

Views: 67

Answers (2)

Vlad from Moscow
Vlad from Moscow

Reputation: 311038

In this alias declaration

using Deduced = typename std::string;

the keyword typename is redundant. Just write

using Deduced = std::string;

The template function Func is a private member function of the class Test. You need to make it public.

The decltype specifier expects an expression. You should write at least like

auto Func() ->  typename Foo::Deduced

Upvotes: 2

Brian Bi
Brian Bi

Reputation: 119239

Remove the decltype.

decltype gives the type of an expression. But Foo::Deduced is already a type, so you can't apply decltype to it. You simply want to refer to that type itself. So all you have to do is write Foo::Deduced.

However, in some contexts, you need to prefix it with typename to tell the compiler that it's really a type. In C++20, you need typename in return Foo::Deduced() but you don't need it in the trailing return type. Prior to C++20, it was needed in both places. Thus your code could be rewritten like so:

template<typename Foo>
auto Func() ->  Foo::Deduced
{
    return typename Foo::Deduced();
}

Or a deduced return type could be used:

template<typename Foo>
decltype(auto) Func()  // notice no trailing return type
{
    return typename Foo::Deduced();
}

Upvotes: 5

Related Questions