6

テンプレートに問題があり、テンプレート化された関数に文字列引数を与えようとすると、コンパイラは "Hello World" を const char [12] として解釈します。const char * にしたいと思います。

各文字列を「const char*」に静的にキャストすることで問題を「回避」できますが、これをロギング システムの一部として使用しようとしているので、シンプルにすることが大きな目標です。

私が言いたいことを説明するのは難しいので、簡単な再現器を考え出しました。main 関数の最後の行がコンパイルされていないことがわかります。

どんな助けでも大歓迎です

#include <string>

// Trivial base class so we can use polymorphism
class StoreItemsBase
{
public:
    StoreItemsBase() {}
};

// Example of a trivial Templated class to hold some 3 items.
// Intent to have similar classes to hold 4,5..n items
template <typename T1, typename T2, typename T3>
class Store3Items : public StoreItemsBase
{
public:
    Store3Items(const T1& t1, const T2& t2, const T3& t3)
    :
    StoreItemsBase(),
    mT1(t1),
    mT2(t2),
    mT3(t3)
    {}

private:
    T1 mT1;
    T2 mT2;
    T3 mT3;
};

// Function to create a pointer to our object with added id
// There would be similar CreateHolderFunctions for 4,5..n items
template <typename T1, typename T2, typename T3>
StoreItemsBase* CreateHolder(const T1& t1, const T2& t2, const T3& t3)
{
    return new Store3Items<T1, T2, T3>(t1, t2, t3);
}

int main()
{
    int testInt=3;
    double testDouble=23.4;
    const std::string testStr("Hello World");

    StoreItemsBase* Ok1 = CreateHolder(testInt, testDouble, testStr);
    StoreItemsBase* Ok2 = CreateHolder(testDouble, testStr, testInt);
    StoreItemsBase* Ok3 = CreateHolder(testStr, static_cast<const char*>("Hello there"), testInt);
    // If you try a standard string, it compiler complains
    // Although I could surround all my strings with the static cast, what I am looking for is a way
    // to for the CreateHolder function to do the work for me
    StoreItemsBase* NotOk4 = CreateHolder(testStr, "Hello World", testInt);

    // Free our objects not shown in the example
}

コンパイラ エラーは次のとおりです。

example.cpp: コンストラクター 'Store3Items::Store3Items(const T1&, const T2&, const T3&) [with T1 = std::basic_string, T2 = char [12], T3 = int]':
example.cpp:50:50: 'StoreItemsBase* CreateHolder(const T1&, const T2&, const T3&) [with T1 = std::basic_string, T2 = char [12], T3 = int]' からインスタンス化
example.cpp:65:74: ここからインスタンス化
example.cpp:21:11: エラー: 初期化子として配列が使用されました
4

2 に答える 2

7

メタ関数を使用して、引数として渡された型をテンプレートに変換できます。文字の配列は次のように変換されますchar*

template< typename T > struct transform
{
    typedef T type;
};

template< std::size_t N > struct transform< char[N] >
{
    typedef char* type;
};
template< std::size_t N > struct transform< const char[N] >
{
    typedef const char* type;
};

Tn次に、直接使用する代わりに、 を使用しますtypename transform< Tn >::type

更新: C++11で作業している場合は、std::decay既に必要なことを行っています。

于 2012-05-17T23:58:44.157 に答える
1

テンプレート引数を const T1 t1、const T2 t2、const T3 t3 に変更してみてください。パフォーマンスは低下しますが、コンパイルされます

テンプレートの引数に基づいて関数の引数を決定することは、多くの場合困難です。これは、クラス コンストラクターの署名に対して試すことができます。クラス "arg_type" (非標準) のテンプレート特殊化を使用して、const ポインターではないすべての引数型が const ref によって渡され、すべての const ポインターが const ポインターとして渡されるようにしました。

また、基本クラスの仮想デストラクタを忘れないでください。そうしないと、悪いことが起こる可能性があります:)

#include <string>

// Trivial base class so we can use polymorphism
class StoreItemsBase
{
public:
    StoreItemsBase() {}
    virtual ~StoreItemsBase() {}
};

template <typename TYPE> class arg_type
{
public:
    typedef const TYPE& type;
};
template <typename TYPE> class arg_type<const TYPE*>
{
public:
    typedef const TYPE* type;
};

// Example of a trivial Templated class to hold some 3 items.
// Intent to have similar classes to hold 4,5..n items
template <typename T1, typename T2, typename T3>
class Store3Items : public StoreItemsBase
{
    typedef typename arg_type<T1>::type arg1;
    typedef typename arg_type<T2>::type arg2;
    typedef typename arg_type<T3>::type arg3;
public:
    Store3Items(arg1 t1, arg2 t2, arg3 t3)
    :
    StoreItemsBase(),
    mT1(t1),
    mT2(t2),
    mT3(t3)
    {}

private:
    T1 mT1;
    T2 mT2;
    T3 mT3;
};

// Function to create a pointer to our object with added id
// There would be similar CreateHolderFunctions for 4,5..n items
template <typename T1, typename T2, typename T3>
StoreItemsBase* CreateHolder(const T1 t1, const T2 t2, const T3 t3)
{
    return new Store3Items<T1, T2, T3>(t1, t2, t3);
}

int main()
{
    int testInt=3;
    double testDouble=23.4;
    const std::string testStr("Hello World");

    StoreItemsBase* Ok1 = CreateHolder(testInt, testDouble, testStr);
    StoreItemsBase* Ok2 = CreateHolder(testDouble, testStr, testInt);
    StoreItemsBase* Ok3 = CreateHolder(testStr, static_cast<const char*>("Hello there"), testInt);
    // If you try a standard string, it compiler complains
    // Although I could surround all my strings with the static cast, what I am looking for is a way
    // to for the CreateHolder function to do the work for me
    StoreItemsBase* NotOk4 = CreateHolder(testStr, "Hello World", testInt);

    // Free our objects not shown in the example
}

クラスは生の const char* を内部に保存するため (std::string を保存するのではなく)、渡される文字列のスコープが、保存しているポインターよりも長く存続することを確認してください。あなたの例のような定数文字列は、永久に存続するため問題ありません。

于 2012-05-18T01:07:27.800 に答える