20

自分では解決できない、シンプルでありながら困難な問題があります。私は次のようなものを持っています

template<class T, class... Args>
T* create(SomeCastableType* args, size_t numArgs)
{
  return new T(static_cast<Args>(args[INDEX_OF_EXPANSION])...);
}

SomeCastableType任意のタイプにキャスト可能であると仮定します。明らかに私が得ることができないのはそれINDEX_OF_EXPANSIONです。

ご助力ありがとうございます。

4

4 に答える 4

22

トリックを示します、イェーイ〜

template<class T, class... Args, std::size_t... Is>
T* create(U* p, indices<Is...>){
  return new T(static_cast<Args>(p[Is])...);
}

template<class T, class... Args>
T* create(U* p, std::size_t num_args){
  assert(num_args == sizeof...(Args));
  return create<T, Args...>(p, build_indices<sizeof...(Args)>{});
}

もちろん、生のポインターの代わりにスマートポインターとを使用することを強くお勧めします。std::vector

于 2013-02-22T00:02:45.357 に答える
3

ヘルパーが必要です:

#include <tuple>

template <typename T, bool, typename Tuple, unsigned int ...I>
struct helper
{
    static T * go(S * args)
    {
        return helper<T, sizeof...(I) + 1 == std::tuple_size<Tuple>::value,
                      Tuple, I..., sizeof...(I)>::go(args);
    }
};

template <typename T, typename ...Args, unsigned int ...I>
struct helper<T, true, std::tuple<Args...>, I...>
{
    static T * go(S * args)
    {
        return new T(static_cast<Args>(args[I])...);
    }
};

template <typename T, typename ...Args>
T * create(S * args)
{
    return helper<T, sizeof...(Args) == 0, std::tuple<Args...>>::go(args);
}

編集:テスト済み、動作しているようです。

于 2013-02-21T23:23:06.110 に答える
3

c ++17のconstexprifを使用すると、インデックスルックアップ関数のはるかに読みやすくわかりやすい実装を取得できます(ここで他の答えに頭を悩ませることはできませんでした)。

template<typename Target, typename ListHead, typename... ListTails>
constexpr size_t getTypeIndexInTemplateList()
{
    if constexpr (std::is_same<Target, ListHead>::value)
        return 0;
    else
        return 1 + getTypeIndexInTemplateList<Target, ListTails...>();
}

これは次のように使用できます。

size_t index = getTypeIndexInTemplateList<X,  Foo,Bar,X,Baz>(); // this will return 2

または、さまざまにテンプレート化されたタイプがあり、その中にインデックスを取得したい場合は、次のようになります。

template<typename... Types>
class Container
{
public:
    size_t getIndexOfType<typename T>() {  return getTypeIndexInTemplateList<T, Types...>(); }
};

...

Container<Foo, Bar, X, Baz> container;
size_t container.getIndexOfType<X>(); // will return 2

それが機能する方法は、リストから型を再帰的に削除することです。したがって、最初の例の呼び出し順序は基本的に次のとおりです。

getTypeIndexInTemplateList<X,  Foo,  Bar,X,Baz>() // ListHead = Foo, ListTails = Bar,X,Baz
getTypeIndexInTemplateList<X,  Bar,  X,Baz>()     // ListHead = Bar, ListTails = X, Baz
getTypeIndexInTemplateList<X,  X,    Baz>()       // ListHead = X, so now we return. Recursive addition takes care of calculating the correct index

関数はconstexprであるため、これはすべてコンパイル時に実行され、実行時には定数になります。

リストに存在しない型を要求すると、テンプレート引数が少なすぎる関数を呼び出そうとするため、コンパイルエラーが発生します。そしてもちろん、タイプが複数回存在する場合、これはリスト内のタイプの最初のインスタンスのインデックスを返すだけです。

于 2020-03-25T17:58:00.250 に答える
2

SomeCastableType任意のタイプにキャスト可能であると仮定します。明らかに私が得ることができないのはそれINDEX_OF_EXPANSIONです。

C ++ 14以降、次のようにヘルパーを使用して、標準ライブラリのサポートで言及されているインデックストリック@Xeoを実行できます。std::make_index_sequence

template<class T, class... Args, std::size_t... Is>
T* create(SomeCastableType* p, std::index_sequence<Is...>)
{
    return new T(static_cast<Args>(p[Is])...);
}

template<class T, class... Args>
T* create(SomeCastableType* p, std::size_t num_args)
{
    return create<T, Args...>(p, std::make_index_sequence<sizeof...(Args)>());
}
于 2019-04-23T08:54:26.487 に答える