メンバー関数はクラステンプレートに特化できないため、ソリューションは「標準準拠」ではありませんでした。これは、関数を部分的に特殊化することはできないという一般的な規則によるものです。したがって、メンバー関数テンプレートの「完全な」特殊化でさえ、完全に特殊化されていないクラスのため、実際には部分的な特殊化です。
私の解決策:
C++11バージョン
私のバージョンでのあなたの例、私はこれがあなたが望むものであると信じています:
int main(){
auto f1 = [](int i){return i*2.54;};
auto f2 = [](int i){ std::stringstream ss; ss << i; return ss.str(); };
MultiUnitValue<int, float, std::string> vv(1, f1, f2);
std::cout << vv.in<int>() << "\n";
std::cout << vv.in<float>() << "\n";
std::cout << vv.in<std::string>() << "\n";
// std::cout << vv.in<long>() << "\n"; // error to compile
}
まず第一に、特別な変換基本クラスが必要です。単一の変換の場合、次のコードフラグメントで、基本クラス関数を介して変換を呼び出すと、このような「指定されていない」変換long
がコンパイルされないことがわかります。
template <class T, class U>
class Conversion {
public:
Conversion(const std::function<U(const T&)>& f) : f(f) {}
U convert (const T& v) const { return f(v); }
private:
std::function<U(const T&)> f;
};
template <class T>
class Conversion<T,T> {
public:
T convert (const T& v) const { return v; }
};
そして、可変個引数テンプレートを使用したクラス:
template <class T, class... V> // V... means all desired conversions
class MultiUnitValue : private Conversion<T,T>, private Conversion<T,V>... {
// allowed conversion: ^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^
public:
MultiUnitValue(T v, const std::function<V(const T&)>&... f) : Conversion<T,V>(f)..., v(v) {}
template <class U>
U in() const
{
// this static assert is not needed - but just to show the message
static_assert(std::is_base_of<Conversion<T,U>, MultiUnitValue<T,V...>>::value,
"Not allowed conversion");
// static_assert is not needed
// since if you MultiUnitValue does not derive from Conversion<T,U>
// - then this call will not compile too
return this->Conversion<T,U>::convert(v);
}
private:
T v;
};
LVSの例: http: //liveworkspace.org/code/05b6ada146cc8f05d027a5536859a087
可変個引数テンプレートのないバージョン:
また、VC ++はまだそれらをサポートしていないため、可変個引数テンプレートなしでソリューションを準備しました。
2番目:変換とカバレッジの制限がT_to_Uタイプに含まれているはずです。
このアプローチでは、C++11バージョンと比較して使用法が少し不便になります。
int main(){
auto f1 = [](int i){return i*2.54;};
auto f2 = [](int i){ std::stringstream ss; ss << i; return ss.str(); };
// next 2 lines differ from C++11 version
typedef ConvertFunctions2<int, float, std::string> CF_f1_f2;
MultiUnitValue<int, CF_f1_f2> vv(1, CF_f1_f2(f1, f2));
std::cout << vv.in<int>() << "\n";
std::cout << vv.in<float>() << "\n";
std::cout << vv.in<std::string>() << "\n";
// std::cout << vv.in<long>() << "\n"; // error to compile
}
これMultiUnitValue
はあなたの例よりも単純で、私のC ++ 11バージョンからでも単純ですが、class CF
はるかに複雑になります。
template <class T, class CF>
class MultiUnitValue {
public:
MultiUnitValue(T v, const CF& cf) : v(v), cf(cf) {}
template <class U>
U in() const
{
return cf.Conversion<T,U>::convert(v);
}
private:
T v;
CF cf;
};
単純な「ヘルパー」変換クラスは、C++11バージョンと同じになります。
template <class T, class U>
class Conversion {
...
};
template <class T>
class Conversion<T,T> {
...
};
そして、VC ++(およびC ++ 03の昔)での可変個引数テンプレートの代替:
template <class T>
class ConvertFunctions0 : public Conversion<T,T> {};
template <class T, class V1>
class ConvertFunctions1 : public Conversion<T,T>, public Conversion<T,V1> {
public:
ConvertFunctions1(std::function<V1(const T&)> f1) : Conversion<T,V1>(f1) {}
};
template <class T, class V1, class V2>
class ConvertFunctions2 : public Conversion<T,T>, public Conversion<T,V1>, public Conversion<T,V2> {
public:
ConvertFunctions2(std::function<V1(const T&)> f1, std::function<V2(const T&)> f2)
: Conversion<T,V1>(f1), Conversion<T,V2>(f2)
{}
};
ご覧のとおりConvertFunctions3
、追加ConvertFunctions4
はそれほど大きな問題ではありません...
ideoneでの完全な例