e271p314
e271p314

Reputation: 4039

Compiling with std::result_of fails when using member function

In the code I attached I am looking for a way to map 1 type to another. The code fails to compile with the error

[root@]# g++ -std=c++11 test.cpp -o test; ./test
test.cpp: In member function ‘void A::Func(AType)’:
test.cpp:32:58: error: template argument 1 is invalid
     using BType = std::result_of<GetBTypeFromAType(AType)>::type;

The compiler version I'm using is 5.3.1, any idea how to fix that?

#include <iostream>
#include <typeinfo>
#include <cxxabi.h>
#include <memory>

template <class T>
std::string GetTypeName()
{
  //http://stackoverflow.com/questions/23266391/find-out-the-type-of-auto/23266701#23266701
  std::unique_ptr<char, void(*)(void*)> name{abi::__cxa_demangle(typeid(T).name(), 0, 0, nullptr), std::free};
  return name.get();
}


struct A
{
  struct AA {};
  struct AB {};
  struct AC {};

  struct BA {};
  struct BB {};
  struct BC {};

  BA GetBTypeFromAType(AA a) { return BA(); }
  BB GetBTypeFromAType(AB a) { return BB(); }
  BC GetBTypeFromAType(AC a) { return BC(); }

  template <typename AType>
  void Func(AType a)
  {
    using BType = std::result_of<GetBTypeFromAType(AType)>::type;
    std::cout << "Func called with " << GetTypeName<AType>() << " and got " << GetTypeName<BType>() << std::endl;
  }
};

int main()
{
  A a;
  A::AA aa;
  A::AB ab;
  A::AC ac;
  a.Func(aa);
  a.Func(ab);
  a.Func(ac);
  return 0;
}

Upvotes: 2

Views: 385

Answers (4)

Jaa-c
Jaa-c

Reputation: 5157

Why don't you just create a simple trait class (provided that you actually don't need the original methods, but really only want mapping of one type to another):

template<typename T>
struct GetBTypeFromAType;

struct A
{
  struct AA {};
  struct AB {};
  struct AC {};

  struct BA {};
  struct BB {};
  struct BC {};

  template <typename AType>
  void Func(AType a)
  {
    using BType = typename GetBTypeFromAType<AType>::type;
    // ...
  }
};

template<> struct GetBTypeFromAType<A::AA> { using type = A::BA; };
template<> struct GetBTypeFromAType<A::AB> { using type = A::BB; };
template<> struct GetBTypeFromAType<A::AC> { using type = A::BC; };

Upvotes: 1

AndyG
AndyG

Reputation: 41220

The tricky thing about std::result_of is that the F(Args...) syntax is misleading. Since it looks like a function, you're tempted to call it like a function. (I think this wonky syntax is part of the reason for its deprecation in C++17)

However, F must be a type not a function name, so saying GetBTypeFromAType is insufficient (you need its type).

However, since it's overloaded, you can't simply wrap it in a decltype; you'd need to cast to the appropriate overload to get a correct pointer, which defeats the entire purpose (because if you knew which overload it would call you wouldn't need to be asking for the return type in the first place)

std::result_of is best used with a function object, so the easiest workaround is to wrap the call to GetBTypeFromAType in a lambda and then use decltype on that lambda:

template <typename AType>
void Func(AType a)
{
  auto wrapper = [this](AType&& a){return GetBTypeFromAType(std::forward<decltype(a)>(a));};
  using BType = typename std::result_of<decltype(wrapper)(AType)>::type;
  std::cout << "Func called with " << GetTypeName<AType>() << " and got " << GetTypeName<BType>() << std::endl;
}

Live Demo (C++11)

The other solutions presented here either assume we can default or aggregate initialize an AType or require that you write a type traits specialization which duplicates information already available at compile time.

Upvotes: 5

user167921
user167921

Reputation: 330

result_of is not what you want. result_of expects a callable, which you are not passing it. You could simplify it by using decltype directly, i.e:

template <typename AType>
void Func(AType a) {
  using BType = decltype(GetBTypeFromAType(AType{}));
  std::cout << "Func called with " << GetTypeName<AType>() << " and got " << GetTypeName<BType>() << std::endl;
}

This outputs:

Func called with A::AA and got A::BA
Func called with A::AB and got A::BB
Func called with A::AC and got A::BC

Upvotes: 1

piwi
piwi

Reputation: 5346

I think you are supposed to give the result type, not the function name, to std::result_of: F(Args...) is a function type with Args... being the argument types and F being the return type..

Maybe can you try to use this instead:

using BType = decltype(GetBTypeFromAType(a));

Example.

Upvotes: 0

Related Questions