14

私は次のクラスを持っています:

struct foo
{
    std::size_t _size;
    int* data;
public:
    explicit foo(std::size_t s) : _size(s) { }
    foo(std::size_t s, int v)
        : _size(s)
    {
        data = new int[_size];
        std::fill(&data[0], &data[0] + _size, v);
    }

    foo(std::initializer_list<int> d)
        : _size(d.size())
    {
        data = new int[_size];
        std::copy(d.begin(), d.end(), &data[0]);
    }

    ~foo() { delete[] data; }

    std::size_t size() const { return _size; }
};

そして、次のように引数を転送したいと思います。

template <typename... Args>
auto forward_args(Args&&... args)
{
    return foo{std::forward<Args>(args)...}.size();
    //--------^---------------------------^
}

std::cout << forward_args(1, 2) << " " << forward_args(1) << " " 
          << forward_args(2) << "\n";

出力を に置き換える{}と、代わりに.()1 1 22 1 1

私のクラスにとって最も理にかなっているのはどれですか?

4

3 に答える 3

1

本当に、このようにクラスを定義するべきではありませんfoo(それがあなたの管理下にある場合)。2 つのコンストラクターにはオーバーラップがあり、2 つの初期化で次のような悪い状況が発生します。

foo f1(3);
foo f2{3};

2 つの異なることを意味します。また、転送関数を作成する必要がある人は、解決できない問題に直面します。これについては、このブログ投稿で詳しく説明しています。またstd::vector、同じ問題に苦しんでいます。

代わりに、「タグ付き」コンストラクターを使用することをお勧めします。

struct with_size {}; // just a tag

struct foo
{
    explicit foo(with_size, std::size_t s);

    explicit foo(with_size, std::size_t s, int v);

    foo(std::initializer_list<int> d);

    // ...
}

これで重複がなくなり、{} バリアントを安全に使用できるようになりました。

于 2016-05-11T11:04:54.743 に答える