CRTP和c ++ 1y返回类型的扣除 [英] CRTP and c++1y return type deduction

查看:113
本文介绍了CRTP和c ++ 1y返回类型的扣除的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我最近玩的是CRTP,当我遇到了一个惊讶我,当使用c ++ 1y函数的类型被推断的东西。以下代码适用:

I was recently playing with CRTP when I came across something that surprised me when used with c++1y functions whose type is deduced. The following code works:

template<typename Derived>
struct Base
{
    auto foo()
    {
        return static_cast<Derived*>(this)->foo_impl();
    }
};

struct Derived:
    public Base<Derived>
{
    auto foo_impl()
        -> int
    {
        return 0;
    }
};

int main()
{
    Derived b;
    int i = b.foo();
    (void)i;
}



我假设来自 Base< Derived> ; :: foo 是返回的表达式的 decltype ,但如果我修改functio foo like this:

I assumed that the return type from Base<Derived>::foo was a decltype of the expression returned, but if I modify the functio foo like this:

auto foo()
    -> decltype(static_cast<Derived*>(this)->foo_impl())
{
    return static_cast<Derived*>(this)->foo_impl();
}

这段代码不再工作,我得到以下错误.1):

This code does not work anymore, I get the following error (from GCC 4.8.1):

||In instantiation of 'struct Base<Derived>':|
|required from here|
|error: invalid static_cast from type 'Base<Derived>* const' to type 'Derived*'|
||In function 'int main()':|
|error: 'struct Derived' has no member named 'foo'|

我的问题是:为什么它不工作?

My questions are: Why doesn't it work? What could I possibly write to get the correct return type without relying on automatic return type deduction?

还有,这里是一个实例

推荐答案

第一个示例工作(返回类型推导)?



类模板的成员函数的定义仅在odr使用(或显式实例化)时隐式实例化。也就是说,通过派生 Base< Derived> ,你可以隐式实例化函数体。

Why does the first example work (return type deduction)?

The definition of a member function of a class template is only implicitly instantiated when odr-used (or explicitly instantiated). That is, by deriving from Base<Derived>, you do not implicitly instantiate the function body. Hence, the return type is still not deduced yet.

在实例化的(*)点, Derived 已完成, Derived :: foo_impl 已声明,返回类型扣除可以成功。

At the (*) point of instantiation, Derived is complete, Derived::foo_impl is declared, and the return type deduction can succeed.

(*)不是the,而是某些实例化点。有几个。


我假设 Base< Derived> :: foo 的返回类型返回一个 decltype
,但是如果我像这样修改函数 foo

I assumed that the return type from Base<Derived>::foo was a decltype of the expression returned, but if I modify the function foo like this:

trailing-return-type 是成员函数声明的一部分;因此,它是周围类的定义的一部分,当从 Base< Derived> 中导出时需要实例化。此时, Derived 仍不完整,特别是 Derived :: foo_impl 尚未声明。

The trailing-return-type is part of the declaration of the member function; hence, it is part of the definition of the surrounding class, which is required to be instantiated when deriving from Base<Derived>. At this point, Derived is still incomplete, specifically Derived::foo_impl has not been declared yet.


我可以写什么来获得正确的返回类型,而没有
依赖于自动返回类型扣除?

What could I possibly write to get the correct return type without relying on automatic return type deduction?

现在这是棘手的。我想说,这不是很清楚地定义在标准,例如。请参阅此问题

Now this is tricky. I'd say this is not very clearly defined in the Standard, e.g. see this question.

这里有一个例子演示了ang ++ 3.4找不到 Derived 内部的成员:

Here's an example that demonstrates that clang++3.4 does not find the members of Derived inside Base<Derived>:

template<typename Derived>
struct Base
{
    auto foo() -> decltype( std::declval<Derived&>().foo_impl() )
    {
        return static_cast<Derived*>(this)->foo_impl();
    }
};

declval 不需要完整类型,因此错误消息是在派生中没有 foo_impl

declval doesn't require a complete type, so the error message is that there's no foo_impl in Derived.

有一个黑客,但我不确定它是否合规:

There's a hack, but I'm not sure if it's compliant:

template<typename Derived>
struct Base
{
    template<class C = Derived>
    auto foo() -> decltype( static_cast<C*>(this)->foo_impl() )
    {
        static_assert(std::is_same<C, Derived>{}, "you broke my hack :(");
        return static_cast<Derived*>(this)->foo_impl();
    }
};

这篇关于CRTP和c ++ 1y返回类型的扣除的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆