【问题标题】:How to typedef the return type of a method from a template class?如何从模板类 typedef 方法的返回类型?
【发布时间】:2017-04-01 00:46:51
【问题描述】:

我有一个模板类 Helper,如下所示:

template< typename Mapper >
class Helper
{
public:

   using mappedType = ... ;

};

我需要mappedTypeMapper 类中map(const int&amp;) 方法返回的类型。给定Mapper 的有效类型,如下所示:

class DMapper
{
public:

    double map(const int& val){ ... }
};

Helper&lt;DMapper&gt;::mappedType 应该是 double。有没有办法在不实例化Mapper 的情况下做到这一点?

我得到的最接近的是:

using mappedType = typename std::result_of<
    decltype(&Mapper::map)(Mapper const*, const int&)
>::type;

但是type在这种情况下没有定义。

编辑:

如果我可以避免对int 使用虚拟参数,那就更好了(在我的具体代码中,参数不是那么简单)。

【问题讨论】:

  • 你真的需要Dmapper中的名字吗?既然你有 C++14,你可以像 auto function(stuff) { return whatever; } 一样使用auto
  • 是的,我知道还有其他方法可以实现我的目标(我需要以Helper 的方法返回std::vectormappedType),这更多是出于好奇:)

标签: c++ types c++14 return-type-deduction


【解决方案1】:

您可以使用std::declval 来使用decltype 中的成员函数,而无需创建实例:

using mappedType = decltype(std::declval<Mapper>().map(0));

std::declval 也可用于参数:

using mappedType = decltype(std::declval<Mapper>().map(std::declval<int>()));

【讨论】:

  • 嗯不错!你可以在不必为方法指定某种虚拟参数的情况下做同样的事情吗(这里为 int 为 0),因为它在现实中并不是那么简单
  • declval 的使用非常巧妙。 :)
  • @Dr_Sam 你为什么关心虚拟参数,是因为它引用了更复杂的类型吗?请记住,您也始终可以使用 declval 作为虚拟参数本身。
  • @Smeeheey 确实,using mappedType = decltype(std::declval&lt;Mapper&gt;().map(std::declval&lt;const int&amp;&gt;())); 工作正常
  • @Dr_Sam:虚拟参数(或再次使用declval)的主要优点是,与您尝试的解决方案转换规则和重载决议不同,它适用。因此,例如,如果我要使用double map(long) 创建一个映射器,它仍然可以工作,同样如果map 有第二个(默认)参数,或者是模板,或者......
【解决方案2】:

我得到的最接近的是

using mappedType = typename std::result_of&lt;decltype(&amp;Mapper::map)(Mapper const*, const int&amp;)&gt;::type;

你几乎明白了。

自动声明的this指针在非常量类方法中不是常量,所以你的

decltype(&Mapper::map)(Mapper const*, const int&)

不匹配Mapper 类中的任何方法。从第一个参数中删除 const 限定符,您的 result_of 解决方案将在没有实例化和虚拟参数的情况下工作:

using mappedType = typename std::result_of<
    decltype(&Mapper::map)(Mapper /*no const here*/ *, const int&)
>::type;

【讨论】:

  • 我没想到我离解决方案这么近...感谢您指出这一点!
  • 我接受这个,因为它与我得到的非常接近,如果 wasthishelpful 的回答同样有效。
  • 是标准中描述的“自动声明”this 指针还是特定于平台的?我必须说这是我第一次看到它明确写成这样(尽管“每个人都知道”这只是另一个论点)。
  • @TheVee 是的,它是标准的。标准的第 9.3.1-9.3.2 节描述了它在所有成员函数中的存在。并且它的声明作为任何非静态方法的第一个参数都是必需的,例如,在第 2.9.12 节 [func.require] 中。另请参阅此问题:stackoverflow.com/questions/26692378/…
  • 如果map 过载,这会中断,这与declval 解决方案不同。
【解决方案3】:

假设Mapper::map不是重载方法,则其返回类型可以自动解析如下:

template< typename Mapper >
class Helper
{
private:
    template<class R, class... T>
    static R resolveReturnType(R (Mapper::*)(T...));

    template<class R, class... T>
    static R resolveReturnType(R (Mapper::*)(T...) const);

public:
    using mappedType = decltype(resolveReturnType(&Mapper::map));
};

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-08-01
    • 2018-02-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多