2014-04-17 81 views
0

虽然试图制定一个C宏来缓解非常量成员函数的写作,调用具有完全相同逻辑的常量成员函数(请参见Effective C++的第1章第3项“避免常量和非常量成员函数中的重复”) ,我相信我在VS2013更新跨越decltype()错误传来1.decltype(* this)VS2013中的错误?

我想用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; 
} 

(可以第一个乱说关于不使用的std :: vector的窟窿)

你可以编译上面的代码并自己看看警告,或者参考我的独立评论来看看VC++会在你身上发生什么。那么你可以! defined(MAKE_THIS_CODE_WORK)表达式有VC++编译代码,因为我除了#else代码工作。

我在这台机器上没有可靠的clang设置,但我能够使用GCC Explorer查看clang是否投诉(click to see/compile code)。它没有。但是,g ++ 4.8会给你一个‘const’ qualifiers cannot be applied to ‘DynamicArray&’错误消息,使用相同的代码。所以也许g ++也有bug?

谈到decltype and auto标准纸(虽然,这几乎是11岁),第6页的最底部说decltype(*this)在非const成员函数应该是T&,所以我敢肯定这应该是合法的...

所以我错误的尝试使用decltype()on * this加上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中的叮当声并没有输出警告,但仍然好奇,尽管输出组件确实显得有些鱼腥味。

+0

我想我的问题可以被认为是这一个的重复(虽然我没有遇到它,而研究我最初的问题)http://stackoverflow.com/questions/7416251/using-decl类型转换为这个到const – kornman00

回答

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名(7.1.3,14.1)或decltype-specifier(7.1.6.2)表示类型TR,它是对类型T的引用,尝试创建类型“左值引用NCE到CVTR“创建类型‘左值参照T’,而试图创建类型‘右值参照CVTR’创建类型TR

decltype(*this)是我们decltype说明符,其表示TR,这是DynamicArray<DatumT>&。这里,TDynamicArray<DatumT>。尝试TR const&是第一种情况,尝试创建(const)TR的左值引用,因此最终结果为T&,而不是const T&。简历资格不在最内层的参考文献中。

+0

谢谢Ben!我用我试图创建的C宏更新了我的问题,以便隐藏这个废话,并避免使用typedef或“this”别名。我仍然很好奇为什么GCC Explorer中的铿锵声没有提出错误甚至是警告......当我回到家时,必须在适当的环境中尝试它。 – kornman00

+0

@ kornman00:在我意识到可以使用'auto'之前,此答案的以前版本建议'template const T&deref_as_const(T * that){return * that; }'使用它来代替所有这些类型特征垃圾。尝试在存在隐式转换时不要使用显式转换。如果你的演员出错了,那么你已经告诉编译器闭嘴,按照它所说的去做。 –

+0

我在哪里使用显式演员?我可以发誓我在发布的所有代码中坚持static_cast(隐式)和const_cast(必需,因为const成员函数返回一个const对象)。当我试图避免向宏本身公开任何细节时,'de_ref_as_const'辅助函数也是好的 – kornman00

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

这是较短,自成体系,具有除__VA_ARGS__ C++ 98兼容,并避免不必要的投

+0

需要在宏中删除“this”的取消引用,但否则会起作用。虽然,DEBUG构建会为每个实例化类型的deref_as_const生成一个函数(更详细的代码密集宏不会),即使您声明为“inline”(至少在VC++中)。 – kornman00

+0

有两个解除引用的好处。 –