【问题标题】:How can I determine the return type of a C++11 member function如何确定 C++11 成员函数的返回类型
【发布时间】:2014-11-24 06:25:17
【问题描述】:

我正在尝试确定各种 C++ 成员函数的返回类型。我知道可以使用 decltype 和 std::declval 来执行此操作,但是我遇到了语法问题并找到了有用的示例。下面的TestCBClass 显示了一个包含混合静态和普通成员函数的哑类示例——带有& 不带参数和返回类型。根据所讨论的方法,我希望能够从每种方法中声明一个返回类型的向量。

在我的应用程序中,这些方法是std::async 的回调,我需要std::future<return types> 的向量。我尝试了各种声明,例如decltype(std::declval(TestCBClass::testStaticMethod))(我不确定在方法名称之前是否需要&)。这种语法是不正确的——当然它不能编译,但我认为它应该使用这种方法。

class TestCBClass {
public:
    TestCBClass(const int& rValue = 1)
        : mValue(rValue) {
        std::cout << "~TestCBClass()" << std::endl;
    }
    virtual ~TestCBClass() {
        std::cout << "~TestCBClass()" << std::endl;
    }
    void testCBEmpty(void) {
        std::cout << "testCBEmpty()" << std::endl;
    }
    int testCBArgRet(const int& rArg) {
        std::cout << "testCBArgRet(" << rArg << ")" << std::endl;
        mValue = rArg;
    }
    static void testCBEmptyStatic(void) {
        std::cout << "testCBEmptyStatic()" << std::endl;
    }
    static void cbArgRetStatic(const SLDBConfigParams& rParams) {
        std::lock_guard<std::mutex> lock(gMutexGuard);
        std::cout << rParams.mPriority << std::endl;
    }
    static std::string testStaticMethod(const PriorityLevel& rPrty) {
        return "this is a silly return string";
    }
private:
    int mValue;
};

【问题讨论】:

    标签: c++ c++11 decltype


    【解决方案1】:

    如果您更喜欢列出参数类型而不是相应的虚拟值,也可以使用std::result_ofdecltype,如下所示:

    #include <iostream>
    #include <utility>
    #include <type_traits>
    
    struct foo {
      int    memfun1(int a) const { return a;   }
      double memfun2(double b) const { return b; }
    };
    
    int main() {
      std::result_of<decltype(&foo::memfun1)(foo, int)>::type i = 10;
      std::cout << i << std::endl;
      std::result_of<decltype(&foo::memfun2)(foo, double)>::type d = 12.9;
      std::cout << d << std::endl;
    }
    

    DEMO here.

    【讨论】:

    【解决方案2】:

    如何确定 C++11 成员函数的返回类型?

    答案:

    您可以像下面的玩具示例一样使用decltypestd::declval

    #include <iostream>
    #include <utility>
    
    struct foo {
      int    memfun1(int a) const { return a;   }
      double memfun2(double b) const { return b; }
    };
    
    int main() {
      decltype(std::declval<foo>().memfun1(1)) i = 10;
      std::cout << i << std::endl;
      decltype(std::declval<foo>().memfun2(10.0)) d = 12.9;
      std::cout << d << std::endl;
    }
    

    LIVE DEMO

    【讨论】:

    • 谢谢,如果 memfun1() 或 memfun2() 带参数会发生什么 - 在我的情况下,我的 testStaticMethod 带一个 PriorityLevel 对象 - 这不是默认可构造的 - 我认为这就是 declval 的用途吗?还有一件事我忘了问我的问题 - 是否可以将类型打印为字符串?
    • @johnco3 你只是放了一些虚拟输入参数。我已经编辑了答案。
    • @johnco3 Yeap declval 确保不会调用对象的构造函数。您可以使用typeid 来获取具有该类型的字符串。你最好使用type_traits,尤其是std::is_same来检查一个类型是否与另一个类型相同。
    • 我检查了你的答案是否有用,但你可能得到了我的回复,因为我也在编辑它:) 不幸的是,我的参数类型不容易用虚拟值创建,有什么方法可以应用 declval也到参数 - 正如我从阅读 declval 文档中了解到的那样,它们“将任何类型 T 转换为引用类型,从而可以在 decltype 表达式中使用成员函数而无需通过构造函数” - 我希望避免整个也为我的论点构建了一个虚拟的东西
    • @johnco3 我本来打算提议std::result_of,但已经有了答案。我也喜欢 Piotr 的回答,你可以选择最适合你的。
    【解决方案3】:

    我尝试过各种声明,例如 decltype(std::declval(TestCBClass::testStaticMethod))

    不必使用 std::declval 并传递实际参数,甚至它们的类型,只要知道什么是静态/非静态成员函数的返回类型。相反,您可以编写自己的 trait 来了解给定函数的返回类型:

    template <typename T>
    struct return_type;
    template <typename R, typename... Args>
    struct return_type<R(*)(Args...)> { using type = R; };
    template <typename R, typename C, typename... Args>
    struct return_type<R(C::*)(Args...)> { using type = R; };
    template <typename R, typename C, typename... Args>
    struct return_type<R(C::*)(Args...) const> { using type = R; };
    template <typename R, typename C, typename... Args>
    struct return_type<R(C::*)(Args...) volatile> { using type = R; };
    template <typename R, typename C, typename... Args>
    struct return_type<R(C::*)(Args...) const volatile> { using type = R; };
    template <typename T>
    using return_type_t = typename return_type<T>::type;
    
    ...
    
    TestCBClass t;
    
    std::future<return_type_t<decltype(&TestCBClass::testCBArgRet)>> a =
            std::async(&TestCBClass::testCBArgRet, t, 1);
    
    std::future<return_type_t<decltype(&TestCBClass::testCBEmpty)>> b =
            std::async(&TestCBClass::testCBEmpty, t);
    
    std::future<return_type_t<decltype(&TestCBClass::testCBEmptyStatic)>> c =
            std::async(&TestCBClass::testCBEmptyStatic);
    

    DEMO

    【讨论】:

    • 非常好 - 它有效(天知道为什么;))类型特征不是我的事 - 尽管 std::result_of 似乎更简单,更容易与模板机制一起使用,所有这些都隐藏在盖子。检查答案是否有用
    • @johnco3: 如果你喜欢在每次声明std::future 时重复函数参数的类型,那么是的,你可以使用std::result_of
    【解决方案4】:

    在编译时推断返回类型的最新语法是这样的:

    std::invoke_result_t<decltype(&Presenter::present), Presenter, QSqlQuery &> someVariable;
    

    让我们考虑一个示例,您想要构造一个具有默认值的对象,例如。 QVector&lt;int&gt;(),但是你需要从模板参数推导出这个类型,在我们的例子中是模板参数Presenter,我们需要推导出一个类方法的返回类型Presenter::present(QSqlQuery &amp;)

    template<typename Presenter>
    inline auto defaultReturnValue() const
    {
        return std::invoke_result_t<decltype(&Presenter::present), Presenter, QSqlQuery &>();
    }
    

    上面的代码推导出这个类的返回类型:

    class VectorPresenter final
    {
    public:
        QVector<int> present(QSqlQuery &query) const;
    };
    

    最后,你会调用:

    const auto defaultValue = defaultReturnValue<VectorPresenter>();
    

    结果是您将在defaultValue 变量中拥有QVector&lt;int&gt; 实例。 现在,您可以创建一个演示者类,它将返回 any 类型,并且您将能够返回该类型的默认值。 ?✨

    【讨论】:

      猜你喜欢
      • 2011-08-30
      • 1970-01-01
      • 1970-01-01
      • 2015-04-29
      • 1970-01-01
      • 1970-01-01
      • 2012-09-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多