次の関数テンプレートについて考えてみます。
template<typename T> void Foo(T)
{
// ...
}
値渡しのセマンティクスは、T
たまたま整数型、または少なくともコピーが安価な型である場合に意味があります。一方、pass-by- [const] -referenceセマンティクスを使用T
することは、コピーするのにコストのかかるタイプである場合に、より理にかなっています。
あなたがライブラリを書いていると少しの間仮定しましょう。理想的には、ライブラリの実装者としてのあなたの仕事は、可能な限り一般的で効率的なクリーンなAPIを消費者に提供することです。では、両方のタイプの引数受け渡し戦略に対応する汎用インターフェースをどのように提供しますか?
これを機能させるための私の最初の試みは次のとおりです。
#include <boost/type_traits.hpp>
template<typename T> struct DefaultCondition
{
enum {value = boost::is_integral<T>::value /* && <other trait(s)> */};
};
template< typename T, class Condition = DefaultCondition<T> > class Select
{
template<bool PassByValue = Condition::value, class Dummy = void> struct Resolve
{
typedef T type;
};
template<class Dummy> struct Resolve<false, Dummy>
{
typedef const T& type;
};
public: typedef typename Resolve<>::type type;
};
典型的な使用法:
template<typename T> class EnterpriseyObject
{
typedef typename Select<T>::type type;
public: explicit EnterpriseyObject(type)
{
// ...
}
};
struct CustomType {};
void Usage()
{
EnterpriseyObject<int>(0); // Pass-by-value.
(EnterpriseyObject<CustomType>(CustomType())); // Pass-by-const-reference.
}
もちろん、これは非クラステンプレートの暗黙的なテンプレート引数の推論を間接的に破ります。
template<typename T> void Foo(typename Select<T>::type)
{
// ...
}
void Usage()
{
Foo(0); // Incomplete.
Foo<int>(0); // Fine.
}
Boost.Typeof
これは、ライブラリとマクロを使用して「修正」できますWinAPI
。
#define Foo(Arg) ::Foo<BOOST_TYPEOF((Arg))>((Arg))
これは単なる準ポータブルハックですが。
ご覧のとおり、私の一般的なアプローチは、すべての場合に本当に満足できるものではありません。
趣味のプログラマーとして、私は実際の経験がなく、参照用の本番品質のコードにアクセスすることもできません。また、これは時期尚早の最適化の悪いケースのように見えるかもしれませんが、私は本当にいくつかのことに興味があります。
- 過去にこのタイプの最適化*を使用したことがありますか?
Boost
(または他のパブリック)ライブラリはすでに同様の機能を提供していますか?- #1または#2の答えが「はい」の場合-非クラステンプレートの場合はどのように処理されますか?
- このようなもので私が見ない明らかな落とし穴はありますか?
- 最後に、これは正気なことでもありますか?
*プロファイルされていません。;)