7

std::enable_ifサブクラスの1つに特定のメンバー関数が定義されている場合、クラスを特殊化するために使用しようとしています。それ以外の場合は、基本クラスで定義されている既定の実装を使用する必要があります。

#include <boost/mpl/list.hpp>
#include <boost/function_types/function_type.hpp>
#include <boost/tti/has_member_function.hpp>

#include <iostream>
#include <type_traits>
#include <memory>

BOOST_TTI_HAS_MEMBER_FUNCTION(f2)

class Base
{
public:
    virtual double f1(double x, double y) const
    {
        std::cout << "Called Base Method" << std::endl;
        return 0.0;
    }
};

template<typename Derived>
class A : public Base
{
public:
    template<typename T = Derived>
    typename std::enable_if
              < has_member_function_f2< T
                                      , double
                                      , boost::mpl::list<double>
                                      , boost::function_types::const_qualified
                                      >::value
              , double
              >::type
    f1(double x, double y) const
    {
        std::cout << "Called Derived Method" << std::endl;
        return static_cast<const Derived* const>(this)->f2(x);
    }
};


class B : public A<B>
{
public:
    double f2(double x) const
    {
        return 1.0;
    }
};

int main()
{
    std::unique_ptr<Base> base_instance( new B );
    std::cout << base_instance->f1(100.0, 10.0) << std::endl;

    B b_instance;
    std::cout << b_instance.f1(100.0, 10.0) << std::endl;

    return 0;
}

私はこれが印刷されることを期待していたでしょう

Called Derived Method
1
Called Derived Method
1

しかし、代わりに私は得る

Called Base Method
0
Called Derived Method
1

オブジェクトのスライスが発生しているようです。誰かが私を助けてくれれば、なぜこれが当てはまるのか、私の人生では理解できません。

それが何らかの形で役立つ場合、これはg ++ 4.7.2でコンパイルされています

4

2 に答える 2

8

テンプレート関数を仮想にすることはできません。これはまた、特定のインスタンス化シグネチャがたまたま一致したとしても、テンプレート関数が基本クラスの仮想関数をオーバーライドしないことを意味します。

A目的を達成するには、メンバーをあるバージョンで提供し、他のバージョンでは提供しないように、全体として特化する必要があります。

于 2014-12-15T17:09:27.377 に答える
3

@ Sebastian の回答で問題が説明されていますが、提案された解決策には問題があります。基本クラスがインスタンス化されたときに派生クラスが完全ではないため、CRTP を使用して派生クラスのプロパティで基本クラス テンプレートを特殊化することはできません。代わりに常にin をオーバーライドf1A、タグ ディスパッチを使用しf2て、派生クラスまたは のデフォルト実装のどちらにディスパッチするかを決定することをお勧めしますBase

template<typename Derived>
class A : public Base
{
    double f1_impl(boost::mpl::true_, double x, double) const
    {
        std::cout << "Called Derived Method\n";
        return static_cast<const Derived*>(this)->f2(x);
    }
    double f1_impl(boost::mpl::false_, double x, double y) const
    {
        return Base::f1(x, y);
    }

public:
    double f1(double x, double y) const override
    {
        using has_f2 = typename has_member_function_f2
            < Derived
            , double
            , boost::mpl::list<double>
            , boost::function_types::const_qualified
            >::type;
        return f1_impl(has_f2{}, x, y);
    }
};

デモ

于 2014-12-15T17:53:48.257 に答える