7

shared_ptr今後のプロジェクトでかなりの量を使用するつもりなので、( を認識していない) の代用としてstd::make_shared可変引数テンプレート関数を書きたいと思いました。コンストラクターに. 以下の最小限の例をコンパイルしようとすると、GCC 4.5.2 から次のようになります。spnew<T>(...)shared_ptrnewinitializer_list

関数 'int main(int, char**)' 内:
関数 'std::shared_ptr spnew(Args ...) [with T = Example, Args = {}]' への引数が多すぎます

関数 'std::shared_ptr spnew(Args ...) [with T = Example, Args = {}]':
'Example::Example()' の呼び出しに一致する関数がありません

奇妙なことに、 を代入すると同等のエラーが発生std::make_sharedspnewます。どちらの場合も、 an が関係しているときにパラメーターを誤って推測しているようで、誤って空としてinitializer_list扱っています。Args...次に例を示します。

#include <memory>
#include <string>
#include <vector>

struct Example {

    // This constructor plays nice.
    Example(const char* t, const char* c) :
        title(t), contents(1, c) {}

    // This one does not.
    Example(const char* t, std::initializer_list<const char*> c) :
        title(t), contents(c.begin(), c.end()) {}

    std::string title;
    std::vector<std::string> contents;

};

// This ought to be trivial.
template<class T, class... Args>
std::shared_ptr<T> spnew(Args... args) {
    return std::shared_ptr<T>(new T(args...));
}

// And here are the test cases, which don't interfere with one another.
int main(int argc, char** argv) {
    auto succeeds = spnew<Example>("foo", "bar");
    auto fails = spnew<Example>("foo", {"bar"});
}

これは単なる私の見落としですか、それともバグですか?

4

2 に答える 2

1

あなたはこれを行うことができます -

#include <memory>
#include <string>
#include <iostream>
#include <vector>

struct Example {

    template<class... Args>
    Example(const char* t, Args... tail) : title(t) 
    {
        Build(tail...);
    }

    template<class T, class... Args>
    void Build(T head, Args... tail) 
    { 
        contents.push_back(std::string(head)); 
        Build(tail...);
    }

    template<class T>
    void Build(T head)
    { 
        contents.push_back(std::string(head)); 
    }

    void Build() {}        

    std::string title;
    std::vector<std::string> contents;

};

template<class T, class... Args>
std::shared_ptr<T> spnew(Args... args) {
    return std::shared_ptr<T>(new T(args...));
}

int main(int argc, char** argv) {
    auto succeeds = spnew<Example>("foo", "bar");
    auto fails = spnew<Example>("foo", "bar", "poo", "doo");

    std::cout << "succeeds->contents contains..." << std::endl;
    for ( auto s : succeeds->contents ) std::cout << s << std::endl;

    std::cout << std::endl << "fails->contents contains..." << std::endl;
    for ( auto s : fails->contents ) std::cout << s << std::endl;
}

contents.push_backこれは、渡された型が に変換できない場合にコンパイラが文句を言うため、ジェネリック テンプレートは型安全であるにもかかわらずconst char *です。

上記のように、コードは gcc 4.6 で正常に動作していましたが、表示される警告はここで説明されてい ますはまだ公開されていないため、変更される可能性があります。

于 2011-07-05T09:32:45.203 に答える
0

gcc-4.7(おそらくgcc-4.6でも動作しますが、分岐したばかりです)で警告が表示されます:

foo.cpp: In function ‘int main(int, char**)’:
foo.cpp:29:47: warning: deducing ‘Args ...’ as ‘std::initializer_list<const 
char*>’ [enabled by default]
foo.cpp:22:20: warning:   in call to ‘std::shared_ptr<_Tp1> spnew(Args ...) 
[with T = Example, Args = {const char*, std::initializer_list<const 
char*>}]’ [enabled by default]
foo.cpp:29:47: warning:   (you can disable this with -fno-deduce-init-list) 
[enabled by default]

しかし、なぜ誰かがinit-listの控除について強化したいと思うのかはわかりません。

関連するスレッドがあります: 私のテンプレートが初期化子リストを受け入れないのはなぜですか

基本的に、裸のinit-listにはタイプがありません。

于 2011-04-27T04:01:26.050 に答える