防止C++ 03代码在C++ 11中执行次优的好方法?

Meh*_*dad 17 c++ visual-c++ move-semantics c++11

我有一些swap为某些类实现的C++ 03代码,以便std::sort快速生成(和其他函数).

不幸的是,std::sort现在似乎使用了std::move,这意味着我的代码现在比C++ 03 得多.

我知道我可以#if __cplusplus >= 201103L用来有条件地定义一个move-constructor/move-assignment操作符,但是我想知道是否有更好的方法不使用预处理器hacks?

(我想避免使用预处理程序,因为它们会很难看,因为我不仅需要测试编译器版本_MSC_VER >= 1600,还因为它们不适用于像LZZ这样不能识别C++的工具11移动语法,但强迫我预处理代码.)

Die*_*ühl 10

似乎问题确实是:如何使用C++ 03编译器实现移动构造函数和移动赋值?

简单的答案是:他们不能!但是,简单的答案忽略了创建一些完全有效的C++ 03代码并且成为移动构造函数并使用C++ 11编译器移动赋值的可能性.这种方法需要使用一些预处理器hackery,但该位仅用于创建定义用于实际实现的一些工具的头.

这是一个简单的头文件,在启用或禁用C++ 11的情况下使用clanggcc进行编译时没有任何警告:

// file: movetools.hpp
#ifndef INCLUDED_MOVETOOLS
#define INCLUDED_MOVETOOLS
INCLUDED_MOVETOOLS

namespace mt
{
#if __cplusplus < 201103L
    template <typename T>
    class rvalue_reference {
        T* ptr;
    public:
        rvalue_reference(T& other): ptr(&other) {}
        operator T&() const { return *this->ptr; }
    };
#else
    template <typename T>
    using rvalue_reference = T&&;
#endif

    template <typename T>
    rvalue_reference<T> move(T& obj) {
        return static_cast<rvalue_reference<T> >(obj);
    }
}

#endif
Run Code Online (Sandbox Code Playgroud)

基本特征是定义一个模板mt::rvalue_reference<T>,其行为有点像C++ 03 的右值引用,实际上T&& C++ 11 的右值引用(即a ).它不会完全处理C++ 03 rvalue引用,但至少允许移动构造函数并移动赋值而不需要实际需要rvalue引用.

注意,这mt::move()只是用于以后显示rvalue_reference<T>即使在C++ 03中也可以移动的方式!重点是rvalue_reference<T>C++ 03编译器能理解的东西或者T&&.对于这个非常合理的表示法,编译器必须支持别名模板.如果不是这种情况,则可以应用相同的技巧,但使用相应类模板的合适嵌套类型.

以下是此标头的示例用法:

#include "movetools.hpp"
#include <iostream>

class foo
{
public:
    foo() { std::cout << "foo::foo()\n"; }
    foo(foo const&) { std::cout << "foo::foo(const&)\n"; }
    foo(mt::rvalue_reference<foo> other) {
        std::cout << "foo::foo(&&)\n";
        this->swap(other);
    }
    ~foo() { std::cout << "foo::~foo()\n"; }
    foo& operator= (foo const& other) {
        std::cout << "foo::operator=(foo const&)\n";
        foo(other).swap(*this);
        return *this;
    }
    foo& operator= (mt::rvalue_reference<foo> other) {
        std::cout << "foo::operator=(foo&&)\n";
        this->swap(other);
        return *this;
    }

    void swap(foo&) {
        std::cout << "foo::swap(foo&)\n";
    }
};

int main()
{
    foo f0;
    foo f1 = f0;
    foo f2 = mt::move(f0);
    f1 = f2;
    f0 = mt::move(f1);
}
Run Code Online (Sandbox Code Playgroud)

也就是说,实际的业务逻辑没有任何预处理器hackery.使用预处理器的唯一需要是在标题中movetools.hpp,不需要混淆.也就是说,其实我觉得它并没有使用预处理黑客定义实际的移动构造函数或虽然预处理器地方使用移动分配.如果你坚持不想使用宏hackery,可以通过指示编译器查看不同的头文件来完成,但这是一个实现细节movetools.hpp.