私はいくつかの既存のコードを書き直しています。以前はすべての回答情報がメモリ内の文字列配列に格納されていました。データ型に基づいて、データは様々な場所で変換されました。以下は私が目指している設定の簡単な模擬です。基本的にいくつかの質問があります。データベースに格納されている回答の構造は、データ型によって異なります。一般的に私はvoid *を扱うことは避け、適切な型にキャストしますが、ラムダを使ってジェネリックコードを実行できるような優れたソリューションを見つけることはできませんでした。すべての解答を同じベクトルに格納する必要があるため、テンプレート化されたクラスは役に立ちません(事前定義されたルールに基づいてすべての解答に算術演算が適用されるため)。タイプセーフなコードと実行時の決定を組み合わせる
アドバイスありがとうございます。
#include <vector>
#include <memory>
struct AddressData
{
wchar_t Line1[50];
wchar_t Line2[50];
long CountrySeqNo;
AddressData()
{
memset(this, 0, sizeof(*this));
};
};
struct GenericData
{
wchar_t value[200];
GenericData()
{
memset(this, 0, sizeof(*this));
};
};
enum class DataType
: short
{
GENERIC,
ADDRESS
};
class AnswerBase
{
protected:
const void* const data;
const DataType dataType;
protected:
AnswerBase(const DataType datatype, const void* const _data)
: dataType(datatype), data(data)
{
if (data == nullptr)
throw std::exception("Data may not be initialized as NULL");
};
public:
/*
Some generic methods here that would apply logic by means of lambdas etc - these would be overwritten in the derived classes
*/
template<typename T> const T& GetData() { static_assert(false, "The given type is not supported"); };
template<>
const GenericData& GetData()
{
if (DataType::GENERIC != dataType)
throw std::exception("The requested type does not match the value that initialised data");
return *static_cast<const GenericData* const>(data);
};
template<>
const AddressData& GetData()
{
if (DataType::ADDRESS != dataType)
throw std::exception("The requested type does not match the value that initialised data");
return *static_cast<const AddressData* const>(data);
};
};
class AddressAnswer
: public AnswerBase
{
public:
AddressAnswer()
: AnswerBase(DataType::ADDRESS, &answer)
{
};
protected:
AddressData answer;
};
class GenericAnswer
: public AnswerBase
{
public:
GenericAnswer()
: AnswerBase(DataType::GENERIC, &answer)
{
};
protected:
GenericData answer;
};
int main()
{
std::vector<std::shared_ptr<AnswerBase>> answers;
answers.push_back(std::make_shared<GenericAnswer>());
answers.push_back(std::make_shared<AddressAnswer>());
// In some parts of code - interact with generic methods without needing to check the underlying data type
// ....
// ....
// In parts of code where we know we are dealing with a given type - like saving to a DB
auto val1 = answers[0]->GetData<GenericData>().value;
auto val2 = answers[1]->GetData<AddressData>().Line1;
// this will give a runtime failure
//auto val3 = answers[0]->GetData<AddressData>().Line1;
return 0;
}
'void *'の代わりに 'varaint'を使うかもしれません。 – Jarod42
私は変種について考えていましたが、VC++はまだC++ 17をサポートしていないので、私はプロジェクトに大きなライブラリではない(大きな問題ではない)。バリアントメンバーは引き続き基本クラスに存在しますか? – Floris