VS2013中的decltype(*this)错误?

kor*_*n00 0 gcc decltype c++11 visual-studio-2013

在尝试制定C宏以简化非const成员函数的编写时,使用完全相同的逻辑调用const成员函数(参见第1章,第3项,"在有效C++中避免const和非const成员函数中的重复" ),我相信我decltype()在VS2013 Update 1中遇到了一个错误.

我想用来在前面提到的宏中decltype(*this)构建一个static_cast<decltype(*this) const&>(*this)表达式,以避免宏调用站点传递任何显式类型信息.但是,在VS2013的某些情况下,后一个表达式似乎没有正确地添加const.

这是一小块代码,我能够回复这个bug:

#include <stdio.h>

template<typename DatumT>
struct DynamicArray
{
    DatumT* elements;
    unsigned element_size;
    int count;

    inline const DatumT* operator [](int index) const
    {
        if (index < 0 || index >= count)
            return nullptr;

        return &elements[index];
    }

    inline DatumT* operator [](int index)
    {
#if defined(MAKE_THIS_CODE_WORK)
        DynamicArray const& _this = static_cast<decltype(*this) const&>(*this);
        return const_cast<DatumT*>(_this[index]);
#else
        // warning C4717: 'DynamicArray<int>::operator[]' : recursive on all control paths, function will cause runtime stack overflow
        return const_cast<DatumT*>(
                static_cast<decltype(*this) const>(*this)
                [index]
            );
#endif
    }
};

int _tmain(int argc, _TCHAR* argv[])
{
    DynamicArray<int> array = { new int[5], sizeof(int), 5 };
    printf_s("%d", *array[0]);
    delete array.elements;

    return 0;
}
Run Code Online (Sandbox Code Playgroud)

(可能第一个关于不使用std :: vector的人应该被重击)

您可以编译上面的代码并自己查看警告,或者参考我的单独评论来查看VC++会向您发出的内容.那你可以!defined(MAKE_THIS_CODE_WORK)VC++编译代码的表达式,除了#else代码工作之外.

我没有在这台机器上设置我可靠的clang,但是我能够使用GCC Explorer查看clang是否抱怨(点击查看/编译代码).它没有.但是,g ++ 4.8将‘const’ qualifiers cannot be applied to ‘DynamicArray&’使用相同的代码给您一条错误消息.那么也许g ++也有bug?

参考decltype和auto标准论文(尽管它已经差不多11年了),第6页的最底层说decltype(*this)在非const成员函数中应该是T&,所以我很确定这应该是合法的......

所以我错误地尝试在*上使用decltype()加上向它添加const?或者这是VS2013中的错误?显然是g ++ 4.8,但是以不同的方式.

编辑:感谢Ben Voigt的回复,我能够弄清楚如何为我想做的事情制作一个独立的C宏.

// Cast [this] to a 'const this&' so that a const member function can be invoked
// [ret_type] is the return type of the member function. Usually there's a const return type, so we need to cast it to non-const too.
// [...] the code that represents the member function (or operator) call
#define CAST_THIS_NONCONST_MEMBER_FUNC(ret_type, ...)   \
    const_cast<ret_type>(                               \
        static_cast<                                    \
            std::add_reference<                         \
                std::add_const<                         \
                    std::remove_reference<              \
                        decltype(*this)                 \
                    >::type                             \
                >::type                                 \
            >::type                                     \
        >(*this)                                        \
        __VA_ARGS__                                     \
    )
// We can now implement that operator[] like so:
return CAST_THIS_NONCONST_MEMBER_FUNC(DatumT*, [index]);
Run Code Online (Sandbox Code Playgroud)

最初的愿望是将这一切隐藏在一个宏中,这就是为什么我不想担心创建typedef或this别名.仍然很奇怪GCC Explorer中的clang没有输出警告......尽管输出组件确实显得很腥.

Ben*_*igt 5

你说自己,decltype (*this)T&. decltype (*this) const &尝试形成对引用(T& const &)的引用. decltype触发参考折叠规则8.3.2p6.但它并没有像你想的那样崩溃.

你可以说decltype(this) const&,但那是T* const&- 对const指针的引用,而不是指向const对象的指针.出于同样的原因,decltype (*this) constconst decltype (*this)没有形成const T&,但是(T&) const.并且const引用上的顶级是无用的,因为引用已经禁止重新绑定.

也许你正在寻找更像的东西

const typename remove_reference<decltype(*this)>::type &
Run Code Online (Sandbox Code Playgroud)

但请注意,添加时根本不需要演员表const.代替

DynamicArray const& _this = static_cast<decltype(*this) const&>(*this);
Run Code Online (Sandbox Code Playgroud)

说啊

DynamicArray const& _this = *this;
Run Code Online (Sandbox Code Playgroud)

这些结合起来

const typename std::remove_reference<decltype(*this)>::type & this_ = *this;
Run Code Online (Sandbox Code Playgroud)

尽管如此,对于一个非常简单和普遍存在的问题,这是一个愚蠢的代码量.说啊:

const auto& this_ = *this;


仅供参考,这是参考折叠规则的文本:

如果typedef-name(7.1.3,14.1)或decltype-specifier(7.1.6.2)表示作为类型TR引用的类型T,则尝试创建类型"lvue reference to cv TR "会创建类型"lvalue"引用T",而尝试创建类型"对cv的 rvalue引用TR"创建类型TR.

decltype(*this)是我们的decltype-specifier表示TR,即DynamicArray<DatumT>&.在这里,TDynamicArray<DatumT>.尝试TR const&是第一种情况,尝试创建(const)的左值引用TR,因此最终结果T&不是const T&.cv资格不在最内层参考之内.