Reputation: 4039
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
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
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;
}
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
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
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));
Upvotes: 0