2

次のような API を使用しようとしています。

#include<iostream>
#include<boost/optional.hpp>

class Base
{
 int id;
public:
 int get_id()
 {
    return id;
 }
};

class A : public Base
{
};

class B : public Base
{
};

class M
{
public:
    enum Type
    {
     t_A,
     t_B
    };
    Type type;
    boost::optional<A&> a;
    boost::optional<B&> b;
    boost::optional<A&> get_A()
    {
        return a;
    }

    boost::optional<B&> get_B()
    {
        return b;
    }

};

派生クラスを介してベースに到達する必要があります。そこで、次のようなテンプレート化された関数を作成しました。

template<class T>
boost::optional<T&> get(M & m)
{
    switch(m.type)
    {
    case M::t_A :
        return m.get_A();
    case M::t_B :
        return m.get_B();
    default:
        throw;
    };
}

int main()
{
    M m;
    //... initialization of m
    int i = get<>(m)->get_id();
    return 0;
}

しかし、私の関数のテンプレート引数は推測できません:

template_sp_1.cpp:63:17: error: no matching function for call to ‘get(M&)’
  int i = get<>(m)->get_id();
                 ^
template_sp_1.cpp:63:17: note: candidate is:
template_sp_1.cpp:46:21: note: template<class T> boost::optional<T&> get(M&)
 boost::optional<T&> get(M & m)
                     ^
template_sp_1.cpp:46:21: note:   template argument deduction/substitution failed:
template_sp_1.cpp:63:17: note:   couldn't deduce template parameter ‘T’
  int i = get<>(m)->get_id();

次のいずれかを試すことはできません。どうやらboost::optional:

int i = get<Base>(m)->get_id();
int i = get<A>(m)->get_id();
int i = get<B>(m)->get_id();

そのようなシナリオに対する解決策はありますか? (APIには触れられません)

4

2 に答える 2

1

@ Manu343726 が既に指摘したように、get()関数にはさまざまな戻り値の型があります。しかし、ABは共通の基本クラスを持っているのでBase、戻り値の型を使用しないのはなぜBase&ですか?

boost 1.58 で修正された参照に関するバグboost::optionalがあるため、少なくともこのバージョンが必要です。あなたの例を修正して、それがどのように機能するかを示しました:

#include <boost/optional.hpp>
#include <boost/version.hpp> 
#include <iostream>


#if BOOST_VERSION < 105800
#error boost version must be at least 1.58
#endif

class Base
{
 int id;
public:
 Base(int id) : id(id) {}
 int get_id()
 {
    return id;
 }
};

class A : public Base
{
public:
    A() : Base(100) {}
};

class B : public Base
{
public:
    B() : Base(999) {}
};

class M
{
public:
    enum Type
    {
     t_A,
     t_B
    };
    Type type;
    boost::optional<A&> a;
    boost::optional<B&> b;
    boost::optional<A&> get_A()
    {
        return a;
    }

    boost::optional<B&> get_B()
    {
        return b;
    }

};


Base& get(M & m)
{
    switch(m.type)
    {
    case M::t_A :
        return (*(m.get_A()));
    case M::t_B :
        return (*(m.get_B()));
    default:
        throw;
    };
}

int main()
{
    A a;
    M m;
    m.type = M::t_A;
    m.a = a;
    Base& base = get(m);
    std::cout << base.get_id() << std::endl;
    return 0;
}

この例では、次のように出力されます。

100

もちろん、これは、有効な参照を含むオプションをAPI が保証するget_A()か、返す場合にのみ、実行時にのみ機能します。get_B()これが保証されない場合は、次のようなものを使用できます。

boost::optional<Base&> get(M & m)
{
    boost::optional<Base&> base;
    switch(m.type)
    {
    case M::t_A:
        base = m.get_A();
        break;
    case M::t_B :
        base = m.get_B();
        break;
    default:
        throw;
    };
    return base;
}
于 2015-06-09T08:54:15.933 に答える