VS2013中的decltype(* this)错误?

时间:2014-04-17 19:58:58

标签: gcc c++11 visual-studio-2013 decltype

尝试制定一个C宏以简化非const成员函数的编写,调用具有完全相同逻辑的const成员函数(参见{第1章,第3章“避免const和非常量成员函数中的重复”) {3}}),我相信我在VS2013 Update 1中遇到了decltype()错误。

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

这是我能够回复错误的一小段代码:

#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;
}

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

您可以编译上面的代码并亲自查看警告,或者参考我的单独评论,看看VC ++会向您发出什么。那你可以!要使VC ++编译代码的defined(MAKE_THIS_CODE_WORK)表达式,除了#else代码之外的其他代码。

我没有在这台机器上设置我可信赖的clang,但是我能够使用GCC Explorer查看clang是否抱怨(Effective C++)。它没有。但是,g ++ 4.8将使用相同的代码为您提供‘const’ qualifiers cannot be applied to ‘DynamicArray&’错误消息。那么也许g ++也有一个bug?

参考click to see/compile code标准文件(虽然它已有近11年历史),第6页的最底部说非{const}成员函数中的decltype(*this)应为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]);

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

2 个答案:

答案 0 :(得分: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 &

但请注意,添加const时根本不需要演员。而不是

DynamicArray const& _this = static_cast<decltype(*this) const&>(*this);

只是说

DynamicArray const& _this = *this;

这些结合到

const typename std::remove_reference<decltype(*this)>::type & this_ = *this;

但是,对于一个非常简单和普遍存在的问题,这是一个愚蠢的代码量。只是说:

<强> const auto& this_ = *this;


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

  

如果 typedef-name (7.1.3,14.1)或 decltype-specifier (7.1.6.2)表示类型TR是对类型T的引用,尝试创建类型“对 cv TR的左值引用”会创建类型“对T的左值引用”,而尝试创建类型“对 cv TR的右值引用”会创建类型TR

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

答案 1 :(得分:0)

关于你的宏

// 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__                                     \
    )

做得更干净

// Cast [this] to a 'const this&' so that a const member function can be invoked
template<typename T> const T& deref_as_const(T* that) { return *that; }

// [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>(deref_as_const(this)__VA_ARGS__)

它更短,自包含,与{+ 1}}兼容,与C ++ 98兼容,并避免不必要的演员