バイナリ互換性を最大限に高めながら複数の POD タイプをサポートする公開 API の推奨設計は何ですか?
-
21-09-2019 - |
質問
私は現在、プリコンパイルされたバイナリ/DLL を必要とする製品用の公開 C++ API を設計しています (クロスプラットフォームになります)。API では、ユーザーがサポートする任意の POD (該当する場合) を使用できるようにしたいと考えていますが、基本的な要件は最大限の柔軟性とバイナリ互換性です。私は CPLEX の API に少し似たようなことをやっています (これはいくつかのインスピレーションの 1 つです) が、(IloInt、IloNum、IloAny、Ilo* に関して) CPLEX の API と少し似た方法で型情報を指定する方法があるかもしれないと考えています。 Var などを参照 リンク (できれば) IloExtractable ブランチの場合)、バイナリ互換性を損なうことなく。私が間違っている?何か考えていることはあるのですが、それが何なのか思い出せません。また、それが機能するかどうかさえ思い出せません。訪問者パターンやデコレータ パターンのようなものに似ていると思いますが、型に関しては、誰かがこの件について教えていただけますか?GoF によるデザイン パターンの本が目の前にあります。
注記:ここに存在する可能性のある構文エラーは、当面の問題の一部ではありません。
使用できないと思われるものとその理由の例:
おそらく..ただし、これにより式ツリーの処理が複雑になる可能性があります。
template<typename ValueType>
Constraint : public Expression;
おそらく今後の展開にも影響が出てくると思います。
IntConstraint : public Expression;
LongConstraint : public Expression;
DoubleConstraint : public Expression;
罪のように醜いので、多くの微妙な問題を引き起こす可能性があります。
union Value
{
int AsInt,
float AsFloat
};
class Constraint : public Expression
{
public:
Value GetValue(Edge);
void SetValue(Value, Edge);
void SetUpper(Value, Vertex);
void SetLower(Value, Vertex);
...
};
編集:マッツ・エルフヘイムへの反応として(そして発見後) このリンク) 今では、テンプレートを可能性から除外する必要がないことに気づきました。これは良いことですが、それが最良のアイデアであるかどうかはまだよくわかりません。少なくとも Constraints クラスに関しては (概念的には適切ですが)、そうでないことを許してください。思った通り明確。
API を使いやすくするために、bnf を使用して文法を定義しました (これは私にとってかなり新しいことです)。これにより、式、制約、および制約と対話するその他のクラスの抽象構文ツリーが作成されました。他のクラスは Constraints とやり取りすることになるため、いわば「最後の瞬間」までは、munch 型の情報をできるだけ渡さないようにしたいと考えています。抽象化のレベルが欠けているのではないかと感じます。
CPLEX を勉強すると、数値 (整数と実数)、一次方程式表現 (もちろん)、それに応じて可能なことの領域に従ってその型をモデル化したという印象を受けます。これはまったく理にかなっています。うーん...
(どうやら私は新規ユーザーなので複数のリンクを投稿できないようです。)
編集2:最初のステップとして、 ConstraintExpressionArgument
Constraint クラスと Expression クラスの間にあるため、操作する型を意識せずに式ツリー内の制約を識別できるのは良いことです。
言及を怠ったかもしれないもう 1 つの詳細は、Constraint クラスがそれ自体では使用できない CPLEX とは異なり、私の Constraint クラスは現在使用可能なユーザー クラスですが、CPLEX と同様に拡張の余地も残しておきたい (つまり、型付けの問題) という点です。 ..
とにかく、現時点では私は同等のものを持っています
class ConstraintExpressionArgument : public Expression;
template<typename ValueType>
class Constraint : public ConstraintExpressionArgument;
解決 2
そうですね、少なくとも今のところは必要なものは揃っていると思います。
前述しました
class ConstraintExpressionArgument : public Expression;
template<typename ValueType>
class Constraint : public ConstraintExpressionArgument;
これにより、型と制約性を分離する正しい軌道に乗ることができました。
他のヒント
ほとんどのシステムでは、 <types.h>
または <inttypes.h>
正確な範囲またはビット数が重要な場合に使用できる型定義を含むヘッダー。この問題に継承を投げかける十分な理由がわかりません。も使用できます std::numeric_limits
ブーストと一緒に BOOST_STATIC_ASSERT()
指定された型またはテンプレート型が要件に一致しない場合に、意味のあるコンパイル時アサートを生成するマクロ。要件としては、整数と浮動小数点、範囲、表現可能な最小値、精度などが考えられます。例えば:
#include <limits>
#include <inttypes.h>
#include <boost/static_assert.hpp>
template<class T, int bits> T Add(const T& a, const T& b)
{
BOOST_STATIC_ASSERT( std::numeric_limits<T>::is_integer );
BOOST_STATIC_ASSERT( std::numeric_limits<T>::is_signed );
BOOST_STATIC_ASSERT( std::numeric_limits<T>::digits == bits );
return a + b;
}
std::numeric_limits にすべての型が含まれていない場合は、テンプレートの特殊化を使用して拡張し、実装します。