【问题标题】:Member function call in decltypedecltype 中的成员函数调用
【发布时间】:2011-07-06 01:43:37
【问题描述】:

以下代码:

struct A
{
    int f(int);
    auto g(int x) -> decltype(f(x));
};

编译失败,报错:

error: cannot call member function 'int B::f(int)' without object

如果我将其更改为:

struct A
{
    int f(int);
    auto g(int x) -> decltype(this->f(x));
};

我收到另一个错误:

error: invalid use of 'this' at top level

其中任何一个有什么问题?我正在使用 gcc 4.6

【问题讨论】:

  • 你试过decltype( declval<A>().f() )吗?我认为这就是 c++0x result_of 的工作原理。见stackoverflow.com/questions/2689709/…
  • @Kitsune,decltype(declval<A>().f())decltype(((A*)0)->f()) 都不起作用,已经尝试过了。请参阅我的答案,了解一些可行的方法,但它很难看。

标签: c++ c++11 decltype member-functions


【解决方案1】:

这里是神奇的词:

struct A
{
    int f(int);
    auto g(int x) -> decltype((((A*)0) ->* &A::f)(x)) ;
};

编辑我从 Mikael Persson 的回答中看到,这是在 boost 中完成的。

【讨论】:

    【解决方案2】:

    result_of 和 decltype 组合可以给出成员函数的返回类型

    #include <type_traits>
    using namespace std;
    
    struct A
    {
        int f(int i) { return i; } 
        auto g(int x) -> std::result_of<decltype(&A::f)(A, int)>::type
        { 
            return x;
        }
    };
    
    
    int main() {
        A a;
    static_assert(std::is_same<decltype(a.f(123)), 
                      decltype(a.g(123))>::value, 
                      "should be identical");
    return 0;
    }
    

    【讨论】:

    • 我提出了一个blog entry,在这有帮助时可以看到不同的用例。
    【解决方案3】:

    目前你只能在函数体内部访问'this'和类的成员,但这可能很快就会改变:

    http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1207

    【讨论】:

    • @YSC - 对,它已移至已修复缺陷列表(并且添加到 C++11 标准中)。
    【解决方案4】:

    Comeau 不喜欢 auto 作为顶级返回类型,但以下编译成功:

    template <typename R, typename C, typename A1> R get_return_type(R (C::*)(A1));
    
    struct A
    {
        int f(int);
        decltype(get_return_type(&A::f)) g(int x);
    };
    

    基本上,您必须声明至少一个额外的构造,以获得您想要的类型。并直接使用decltype

    编辑:顺便说一句,这也适用于深入研究成员函数的返回类型:

    template <typename R, typename C, typename A1> R get_return_type(R (C::*)(A1));
    
    struct B { int f(int); };
    
    struct A
    {
        int f(int);
        B h(int);
    
        decltype(get_return_type(&A::f)) g(int x);
    
        decltype(get_return_type(&A::h).f(0)) k(int x);
    };
    
    int main()
    {
        return A().k(0);
    }
    

    当然,它不像auto f()-&gt; ... 那样方便,但至少它可以编译。

    【讨论】:

    • 另外,如果 f 是模板成员函数,这将不起作用,除非您明确选择正确的重载,这使得它更加冗长
    • @HighCommander4 你问是否有不那么丑陋的方法来做到这一点?我认为答案是否定的,这正是您提出的原因。
    【解决方案5】:

    经过一些测试,decltype(declval&lt;A&gt;().f(x))decltype(((A*)0)-&gt;f(x)) 都不起作用。

    但是,使用 boost::bind 似乎可以工作(而且它是“幕后”版本):

    struct A
    {
        int f(int);
        auto g(int x) -> decltype(boost::bind(&A::f,0,x)());
        auto h(int x) -> decltype((((A*)0)->*(&A::f))(x)); //similarly (what Boost.Bind does under-the-hood.
    };
    

    当然,这并不漂亮。我想你可以看看 boost::bind 是如何做到的,也许会找到一个更好的解决方案。

    编辑

    按照 MSN 的建议,您也可以制作自己的函数模板来解决此问题:

    template< typename R, typename C, typename... Args > R member_func(R (C::*)(Args...)); 
    
    struct A
    {
        int f(int);
        auto g(int x) -> decltype(member_func(&A::f));
    };
    

    【讨论】:

    • 它不起作用。我得到:error: invalid use of incomplete type 'A'。即使它有效,它也会非常冗长,尤其是在返回表达式中有多个成员函数调用时。
    • 好点,A 不完整。尝试使用指针。查看我的编辑。
    • 指针版还给error: invalid use of incomplete type 'A'
    【解决方案6】:

    在我看来,这不起作用,因为 decltype 在方法之外,而 A 在那一刻是一个不完整的类型(所以你甚至不能做A().f(x))。

    但你不应该真的需要那个。在 A 的声明之外,这将按预期工作,在 A 中,您应该知道上面几行声明的函数的返回类型。或者你可以写:

    struct A {
        typedef int ret_type;
        ret_type f(int x);
        ret_type g(int x);
    };
    

    这甚至适用于普通的 c++03。

    【讨论】:

    • 我给出的例子显然是为了突出问题而简化的。在我的实际代码中,f 的返回类型不是“int”,而是一些复杂的表达式,涉及到 Boost.Range 转换、bind-expression 等(实际上 f 本身使用 decltype 来声明它的返回类型)。跨度>
    • @HighCommander:所以你设法声明了一次返回值,但没有第二次?
    • @UncleBens:不,一次都没有。正如我所说, f 本身使用 decltype 来声明其返回类型。
    • 你试过typedef decltype(...) ret_type;吗?
    • 是的,同样的问题。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-09-27
    • 1970-01-01
    • 1970-01-01
    • 2012-07-06
    • 2019-12-02
    • 1970-01-01
    相关资源
    最近更新 更多