【问题标题】:Compiling with std::result_of fails when using member function使用成员函数时使用 std::result_of 编译失败
【发布时间】:2018-01-10 12:35:28
【问题描述】:

在我附加的代码中,我正在寻找一种将一种类型映射到另一种类型的方法。代码编译失败,报错

[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;

我使用的编译器版本是 5.3.1,知道如何解决这个问题吗?

#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;
}

【问题讨论】:

  • (无关紧要,但不要以 root 身份进行开发工作。只有在真正需要时才提升权限。)

标签: c++ c++11


【解决方案1】:

std::result_of 的棘手之处在于 F(Args...) 语法具有误导性。因为它看起来像一个函数,所以你很想把它当成一个函数来调用。 (我认为这种古怪的语法是它在 C++17 中被弃用的部分原因)

但是,F 必须是 type 而不是函数名,所以说 GetBTypeFromAType 是不够的(您需要它的 type)。

但是,由于它已重载,您不能简单地将其包装在 decltype 中;您需要强制转换为适当的重载以获得正确的指针,这会破坏整个目的(因为如果您知道它将调用哪个重载,则不需要首先询问返回类型)

std::result_of 最好与函数对象一起使用,因此最简单的解决方法是将对 GetBTypeFromAType 的调用包装在 lambda 中,然后在该 lambda 上使用 decltype

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)

这里介绍的其他解决方案要么假设我们可以默认或聚合初始化 AType,要么要求您编写一个类型特征特化来复制编译时已经可用的信息。

【讨论】:

    【解决方案2】:

    result_of 不是你想要的。 result_of 需要一个 callable,但您没有传递它。您可以通过直接使用decltype 来简化它,即:

    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;
    }
    

    这个输出:

    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
    

    【讨论】:

    • 我会使用你的代码,这比 result_of 容易得多,但问题是关于 result_of 所以我接受了@AndyG 的回答
    【解决方案3】:

    你为什么不创建一个简单的 trait 类(前提是你实际上不需要原始方法,但真的只想将一种类型映射到另一种类型):

    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; };
    

    【讨论】:

    • 由于某种原因,我的代码中的模板专业化存在一些问题,使用重载函数对我来说非常有用。不过,您的解决方案可能是将一种类型映射到另一种类型的最佳解决方案
    【解决方案4】:

    我认为您应该将结果类型而不是函数名称提供给std::result_of:F(Args...) is a function type with Args... being the argument types and F being the return type.

    也许您可以尝试使用它:

    using BType = decltype(GetBTypeFromAType(a));
    

    Example.

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-01-26
      • 1970-01-01
      • 1970-01-01
      • 2019-12-02
      • 1970-01-01
      相关资源
      最近更新 更多