2

同じように使用される一連の関数に統一されたインターフェイスを提供するにはどうすればよいでしょうか? 説明のために、与えられたライブラリ関数のセットを見てください:

/* existing library functions */
/* the signatures are different: some return int, some float */

/* set of input related functions */
int getInputValue() { return 42; }
size_t getInputSize() { return 1; }

/* set of output related functions */
int getOutputValue() { return 21; }
size_t getOutputSize() { return 1; }

/* set of parameter related functions */
float getParameterValue() { return 3.14; }
size_t getParameterSize() { return 1; }

同じように使用されると仮定します。

if (getSize() > 0) {
  T value = getValue()

getSize()A) 提供する良い方法は何getValue()ですか?

最初に、テンプレート メソッド パターンが必要だと思いましたが、適用できませんでした。これは、テンプレート メソッド パターンのワーカーとは対照的に、関数のシグネチャが異なるためです。

だから私が代わりにしたこと:

/* I want to provide a uniform interface */

/* the specific part of inputs, outputs and parameters is in the traits */
struct input_traits {
  typedef int value_type;
  static int getValue() { return getInputValue(); }
  static size_t getSize() { return getInputSize(); }
};

struct output_traits {
  typedef int value_type;
  static int getValue() { return getOutputValue(); }
  static size_t getSize() { return getOutputSize(); }
};

struct parameter_traits {
  typedef float value_type;
  static float getValue() { return getParameterValue(); }
  static size_t getSize() { return getParameterSize(); }
};


/* the common part (they are used in the same way) is in the Helper */
template<typename traits>
class CommonUsage {
public:
  void use()
  {
    if (traits::getSize() > 0) {
      typename traits::value_type value = traits::getValue();
    }
  }
};

int main()
{
  CommonUsage<input_traits>().use();
  CommonUsage<output_traits>().use();
  CommonUsage<parameter_traits>().use();
}

B) これは良いアプローチですか?

4

2 に答える 2

2

A. 私があなたの質問を正しく理解していれば、抽象クラスを使用する必要があります。次のコードを見てください。本質的にはあなたのコードと同じです。

これは私がそれを行う方法です。

#include <iostream>

template <typename value_type>
class Traits {
public:
    virtual value_type getValue() const = 0;
    virtual size_t getSize() const = 0;

    virtual ~Traits() { }
};

class input_traits: public Traits <int>{
public:
    virtual int getValue() const {
        return 42;
    }

    virtual size_t getSize() const {
        return 1;
    }
};

class parameter_traits: public Traits <double>{
public:
    virtual double getValue() const {
        return 3.14;
    }
    virtual size_t getSize() const {
        return 1;
    }
};

class CommonUsage {
public:
    template <typename value_type>
    void use(const Traits<value_type>& traitsObject) {
        if (traitsObject.getSize() > 0) {
            std::cout << traitsObject.getValue();
        }
    }
};

int main() {
    CommonUsage().use(parameter_traits());
    return 0;
}
于 2012-10-12T15:38:57.017 に答える
0

ユーザーの回答に代わるものとして(今回はテンプレートの特殊化を使用)は次のとおりです。

template <class T>
struct traits {
    T getValue() const {  throw std::runtime_exception("..."); }
    size_t getSize() const { return 0; }        
}; 


template <>
struct traits<int> {
    int getValue() const { return 42; }
    size_t getSize() const { return 1; }
};

template <>
struct traits<float> {
    int getValue() const { return 3.145; }
    size_t getSize() const { return 1; }
};

// do template aliasing
using input_traits = traits<int>;
using parameter_traits = traits<float>;

struct CommonUsage {
    template <typename T>
    static void use(const traits<T> &traits) {
        if (traits.getSize() > 0)
            std::cout << traits.getValue() << std::endl;
    }
};

int main(int arg, char **argv) {
    CommonUsage::use(input_traits());
    CommonUsage::use(parameter_traits());
}

どちらのアプローチにも利点/欠点があります。テンプレートの特殊化を使用すると、仮想メソッドのオーバーヘッドは発生しません。

于 2012-10-12T16:46:17.290 に答える