4

特定のテンプレート化されたクラスから派生した型のみにパラメーターを制限する関数が必要です。この場合、basic_string(STL- docsから)。たとえば、 awstringは次のように宣言されています。

typedef basic_string<wchar_t, char_traits<wchar_t>, allocator<wchar_t> >
wstring;

基本的な考え方は次のようになります。

template <class TString>
void strings_only_please(TString message) {
    static_assert(is_base_of<basic_string, TString>::value, 
        "Not a string type!");  
}

もちろん、それはコンパイルされませんが、basic_string が指定されていないためです...実際の型が必要です。(いくつかの実際の文字列型をハードコーディングすることもできますが、このパターンの一般的な解決策を探しています。)

私は Visual Studio 2012 を使用していますが、理想的には、コードを GCC などの他の最新の C++ コンパイラに移植できるようにしたいと考えています。

4

1 に答える 1

10

問題を解決するには 3 つの方法があります。1 つは の実装、もう 1 つはis_specialization_of関数に のstd::basic_string<T1,T2,T3>代わりに を使用する方法TString、3 つ目は 2 番目の解決策と同じ哲学を持ちます。だけでテンプレートをマッチ可能にしstd::basic_stringます。


is_base_of次の 2 つの理由から、この例では十分ではありません。

  1. is_base_ofタイプUが派生してTいるかどうか(または同じタイプであるかどうか)を確認するために使用されます。スニペットには継承が含まれていません。

  2. std::basic_string完全なタイプではないため、まったく使用できませんis_base_of(すでに指摘しました)。


ソリューション #1

is_specialization_oftype が不完全なtypeUの特殊化であるかどうかを確認するために使用されます。以下の例のように、テンプレート テンプレート クラスを使用して実装するのは非常に簡単です。T

@SebastianRedl で指摘されているように、VS2012 を使用して variadic テンプレートを使用することはできません。他のソリューションを参照してください (一般的ではありませんが、ニーズには十分です)。

#include <type_traits>
#include <iostream>
#include <string>

template<template<typename...> class T, typename U>
struct is_specialization_of              : std::false_type { };

template<template<typename...> class T, typename... Ts> 
struct is_specialization_of<T, T<Ts...>> : std::true_type  { };

int
main (int argc, char *argv[])
{
  std::cerr << is_specialization_of<std::basic_string, std::string >::value << std::endl;
  std::cerr << is_specialization_of<std::basic_string, std::wstring>::value << std::endl;
  std::cerr << is_specialization_of<std::basic_string, std::istream>::value << std::endl;
}

出力

1
1
0

解決策 2

template <typename T1, typename T2, typename T3>
void strings_only_please(std::basic_string<T1,T2,T3>) {
  // ...  
}

確かに、上記は良いstatic_assertエラーにはなりませんが、それはあなたのニーズには十分であり、あなたが望むことをします; この関数は、特化した型によってのみ呼び出すことができますstd::basic_string


解決策 #3

template<typename T>
struct is_basic_string : std::false_type { };

template<typename T1, typename T2, typename T3>
struct is_basic_string<std::basic_string<T1,T2,T3>> : std::true_type { };

...

is_basic_string<std::string >::value // true
is_basic_string<std::istream>::value // false
于 2013-07-10T15:17:20.800 に答える