2

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"

Zebrafish
  • 11,682
  • 3
  • 43
  • 119
  • 2
    Highly relevant/dupe of first half of your question: https://stackoverflow.com/questions/610245/where-and-why-do-i-have-to-put-the-template-and-typename-keywords – StoryTeller - Unslander Monica Oct 03 '17 at 10:09
  • 1
    And the MSVC implementation of templates wasn't compliant for ages. [Only now did they implement it](https://blogs.msdn.microsoft.com/vcblog/2017/09/11/two-phase-name-lookup-support-comes-to-msvc/). – StoryTeller - Unslander Monica Oct 03 '17 at 10:10
  • 2
    With `T()` you are not calling the closure's call operator, rather, you are declaring a function which returns that lambda. Also, you should really ask one question per question please. – Rakete1111 Oct 03 '17 at 10:11

1 Answers1

5

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;
Daniel Trugman
  • 8,186
  • 20
  • 41
  • It isn't perfectly fine; there are subtle corner cases where it fets the result wrong. Which is why it was deprecated. – Yakk - Adam Nevraumont Oct 03 '17 at 11:14
  • @Yakk, I wasn't aware of such corner cases. I removed my comment on the matter while I look for formal references on the matter. Can you point me to relevant information? – Daniel Trugman Oct 03 '17 at 11:16
  • Why would result_of be replaced by invoke_result if decltype and declval can do the same thing? Or can't they? – Zebrafish Oct 03 '17 at 11:26
  • @DanielTrugman There is a question about it :) https://stackoverflow.com/questions/46021734/what-is-the-reason-for-stdresult-of-deprecated-in-c17 – Rakete1111 Oct 03 '17 at 11:27
  • @Zebrafish, there are many things you can in multiple ways in C++, but you want the language to be as simple as possible. – Daniel Trugman Oct 03 '17 at 11:31
  • @Zebrafish Easier to use SFINAE with, among other advantages (can invoke member functions, member variables, ...). You can do those with `decltype`, but it's cleaner with `std::invoke_result`. – Rakete1111 Oct 03 '17 at 11:31
  • @DanielTrugman Basically, types in function signatures are modified (decayed) in certain ways, and it applies to the types in the signature arguement of `std::result_of`. – Yakk - Adam Nevraumont Oct 03 '17 at 12:55