3

次のコードを検討してください。

template <int dim>
struct vec
{
    vec normalize();
};


template <>
struct vec<3>
{
    vec cross_product(const vec& second);
    vec normalize();
};

template <int dim>
vec<dim> vec<dim>::normalize()
{
    // code to normalize vector here
    return *this;
}

int main()
{
    vec<3> direction;
    direction.normalize();
}

このコードをコンパイルすると、次のエラーが発生します。

1>main.obj : エラー LNK2019: 未解決の外部シンボル "public: struct vec<3> __thiscall vec<3>::normalize(void)" (?normalize@?$vec@$02@@QAE?AU1@XZ) が参照されました関数 _main で

4

3 に答える 3

9

あなたはできません:)あなたが望むのは、代わりにメンバー関数を特殊化することです:

template <int dim>
struct vec
{
    // leave the function undefined for everything except dim==3
    vec cross_product(const vec& second);
    vec normalize();
};

template<>
vec<3> vec<3>::cross_product(const vec& second) {
    // ...
}

template <int dim>
vec<dim> vec<dim>::normalize()
{
    // code to normalize vector here
    return *this;
}

別の、もう少し複雑な解決策は、次を使用することboost::enable_ifです。

template <int dim>
struct vec
{
    // function can't be called for dim != 3. Error at compile-time
    template<int dim1>
    typename boost::enable_if_c< dim == dim1 && dim1 == 3, vec<dim1> >::type 
    cross_product(const vec<dim1>& second) {
        // ...
    }
    vec normalize();

    // delegate to the template version
    void without_params() {
        // delegate
        this->without_params<dim>();
    }

private:
    // function can't be called for dim != 3. Error at compile-time
    template<int dim1>
    typename boost::enable_if_c< dim == dim1 && dim1 == 3 >::type 
    without_params() {
        // ...
    }   
};

template <int dim>
vec<dim> vec<dim>::normalize()
{
    // code to normalize vector here
    return *this;
}

これにより、任意の dim != 3 に対して cross_product が呼び出されると、コンパイル時エラーが発生します。「トリック」は、パラメーターを持つ関数に対してのみ機能することに注意してください。これは、テンプレート パラメーターを自動推定できるからです。パラメータのない場合、上記の関数を提供しましたwithout_parameters:)。

于 2008-12-07T01:59:10.247 に答える
2

vec<3>::normalize の定義を提供していないため、リンカーは明らかにそれにリンクできません。

テンプレートの特殊化の全体的なポイントは、各メソッドの特殊化されたバージョンを提供できることです。この場合、実際にはそうしないことを除いて。

于 2008-12-07T01:51:19.043 に答える
1

私が知る限り、「一般的な」バージョンを呼び出すことはできません。

または、クラスの外部で一般的な実装を関数として定義することもできます。

template <int dim>
struct vec
{
};

namespace impl {
    template <int dim>
    vec<dim> normalize(const vec<dim>& v)
    {
        // code to normalize vector here
        return v;
    }
}

template <>
struct vec<3>
{
    vec cross_product(const vec& second);
    vec normalize() { return impl::normalize(*this); }
};


int main()
{
    vec<3> direction;
    direction.normalize();
}
于 2008-12-07T01:52:36.653 に答える