Zebrafish
Zebrafish

Reputation: 14434

I'm not understanding these uses of std::result_of and decltype

On my Visual Studio project I had the following and it worked fine:

template <typename T>
void function(T type)
{

    std::result_of<T()>::type myVar = 5; // This compiled fine with Visual Studio, 
but with GCC it shows the following errors:
    //error: dependent-name ‘std::result_of<T()>::type’ is parsed as a non-type, 
    //but instantiation yields a type. note: say ‘typename std::result_of<T()>::type’ if a type is meant
}

int main() {

    auto lambda = []() { return float(); };
    function(lambda);
    return 0;
}

I just want to understand, is the compiler insisting that I preface the std::result_of with "typename" because it could be ambiguous, in that std::result_of could return a class, and then ::type could be a member of that class? Is that why it's insisting that typename be added? If this is the case then why does Visual Studio allow it? Is it non compliant?

Also, because I've read that result_of is being deprecated as of C++14 or C++17, I wanted to try and use the more generic decltype, which is supposed to work in more circumstances. So I tried:

template <typename T>
void function(T type)
{
decltype(T()) myVar = 5; // Error, use of deleted function‘main()::<lambda()>::<lambda>()’  main.cpp    
}

So I'm aware that a lambda has a deleted default constructor and copy assignment operator, but in this case I really think that when passing the lambda to this templated function the lambda's copy constructor is called, which it does have. Then when I do decltype(T()) I assume this would be calling its operator() function. I don't understand why it says something about deleted function.

And finally I tried with:

decltype(std::declval<T()>) myVar = 5;

Because I thought that declval can be used as if creating a fake instance of whatever call you make, at least that's how it was explained to me. This also fails with error:

"invalid initialization of reference of type ‘main()::&&’ from expression of type ‘int"

Upvotes: 2

Views: 1308

Answers (1)

Daniel Trugman
Daniel Trugman

Reputation: 8511

result_of

First, the GCC compiler requires the keyword typename before std::result_of because the return value of the latter is a class. And you have to instruct it to use its type to declare a new variable.

Regarding your comment:

Also, because I've read that result_of is being deprecated as of C++14 or C++17

std::result_of is deprecated as of C++17 (See here why) and is replaced by the newly introduced std::invoke_result, so you could use it instead if you have a compliant compiler.

decltype

Since std::result_of is declared in terms of decltype in the following manner:

  template<typename _Signature>
  struct result_of;

  template<typename _Functor, typename... _ArgTypes>
  struct result_of<F(Args...)> {
      typedef decltype( std::declval<F>()(std::declval<Args>()...) ) type;
  };

You could use a similar definition:

decltype( std::declval<T>()() ) myVar = 5;

Upvotes: 5

Related Questions