1. ホーム
  2. c++

[解決済み] テンプレート化されたクラスのC++キャスト

2022-02-12 11:44:58

質問

テンプレートについて質問です。テンプレート化されたクラスで、例えばfloatやdoubleの配列を持ちたいのですが、どのようにすればよいのでしょうか?

それを複製するclone()関数を書けばいいんです。問題ありません。しかし、doubleとfloatの間を行き来するcast()という別の関数が欲しいです。これは以前にも多少話題になりましたが、問題が同じとは思えません。

stackoverflow.com/questions/714213/c-template-casting

私が抱えている問題は、リンカーエラーではなく、コンパイラーエラーです。エラーメッセージは

main.cpp: In function `void caster()':
main.cpp:63: error: expected primary-expression before "double"
main.cpp:63: error: expected `;' before "double"
main.cpp:64: error: expected primary-expression before "float"
main.cpp:64: error: expected `;' before "float"
main.cpp:65: error: expected primary-expression before '>' token
main.cpp:65: error: expected primary-expression before ')' token

下のコードをダンプしてみました。63、64、65行目は、"Error here"とコメントしたところです。

ちなみに、私のコンパイラは "GNU C++ version 3.4.5 20051201 (Red Hat 3.4.5-2) (x86_64-redhat-linux) compiled by GNU C version 3.4.5 20051201 (Red Hat 3.4.5-2)"です。

ググってみたところ、すでにこの問題を経験した人がいることが判明しました。

gcc.gnu.org/ml/gcc-help/2006-04/msg00022.html

ここに解決策があります。

gcc.gnu.org/ml/gcc-help/2006-04/msg00023.html

しかし、元の投稿者が次のように尋ねています。 なぜ その答えは、あまり明確ではありません。

gcc.gnu.org/ml/gcc-help/2006-04/msg00025.html

残念ながらリンク切れで、Stroustrupの第3版も持っていない。今、私は修正し、私のコードが動作するようになりました。しかし、Stackoverflow, なぜ はうまくいくのでしょうか?


#include <stdio.h>

// =================== This would be the header ===================
template <class T>
class foo
{
public:
             foo(const T val) {d_data = new double; *d_data = val;}
    virtual ~foo() {delete d_data;};

    foo* clone() const;

    template<class U>
    foo<U>* cast() const;

private:
    double *d_data;
};

// =================== This would be the implementation of the class ===================
template<class T>
foo<T>* foo<T>::clone() const
{
    return new foo<T>(*d_data);
}

template<class T>
template<class U>
foo<U>* foo<T>::cast() const
{
    return new foo<U>(*d_data);
}

template class foo<float>;
template class foo<double>;

template foo<float>* foo<float>::cast() const;
template foo<float>* foo<double>::cast() const;
template foo<double>* foo<float>::cast() const;
template foo<double>* foo<double>::cast() const;

// =================== Using the class ===================
template <class T>
void caster()
{
    foo<double> *f1 = NULL;
    foo<float>  *f2 = NULL;
    foo<T>      *f3 = NULL;

    // I am looking at something that compiles
    // I don't care about linking for now
    // This will crash at runtime because of
    // NULL, but that's just an example

    f1->cast<double>(); // compiler OK
    f1->cast<float>();  // compiler OK
    f1->cast<T>();      // compiler OK

    f2->cast<double>(); // compiler OK
    f2->cast<float>();  // compiler OK
    f2->cast<T>();      // compiler OK

    f3->cast<double>(); // Error here
    f3->cast<float>();  // Error here
    f3->cast<T>();      // Error here

    f3->foo<T>::template cast<double>(); // It works!
    f3->foo<T>::template cast<float>();  // It works!
    f3->foo<T>::template cast<T>();      // It works!
}

int main(int argc, char **argv)
{
    return 0;
}

解決方法は?

f3->cast<double>(); // Error here 

この行では、コンパイラは < の後に f3->cast は、テンプレート引数の先頭か、小比較演算子を意味するものと思われます。

テンプレート引数の先頭を意味することを明示的に指定すること。正しい方法は

f3->template cast<double>();

まとめると .template 記法(および ->template は,テンプレートの内部でのみ使用し,テンプレート・パラメータに依存するもの(例えば,式 f3 これはテンプレートパラメータ T )