6

私は次の問題を抱えています:

template<class T>
void set(std::string path, const T data)
{
   stringstream ss;
   ss << data << std::endl;
   write(path, ss.str();
}

template<class T>
void set(std::string path, const T data)
{
    std::stringstream ss;
    for(typename T::const_iterator it = data.begin(); it < data.end(); ++it)
    {
       ss << *it;
       if(it < data.end() -1 )
          ss << ", ";
    }
    ss << std::endl;
    write(path, ss.str());
}

次のエラーが発生します。

error: ‘template<class T> void myclass::set(std::string, T)’ cannot be overloaded
error: with ‘template<class T> void myclass::set(std::string, T)’

テンプレート内のコンテナタイプと他のタイプを区別する方法はありますか?

4

4 に答える 4

8

特性を使用する:

#include <type_traits>

template <typename T>
typename std::enable_if<is_container<T>::value>::type
set (std::string const & path, T const & container)
{
    // for (auto const & x : container) // ...
}


template <typename T>
typename std::enable_if<!is_container<T>::value>::type
set (std::string const & path, T const & data)
{
    std::ostringstream oss;
    oss << data;
    write(path, oss.str());
}

きれいなプリンタコードで適切な特性を見つけることができます。

于 2012-07-19T09:42:57.787 に答える
6

C ++ 03では、少しのSFINAEを使用してこれを実行し、さまざまなタイプの関数のさまざまなバージョンを選択的に有効にすることができます。

#include <boost/type_traits.hpp>
#include <sstream>
#include <iostream>
#include <vector>

using namespace std;

template<class T>
void set(typename boost::enable_if<boost::is_pod<T>, std::string>::type path, const T data)
{
   std::cout << "POD" << std::endl;
   stringstream ss;
   ss << data << std::endl;
}

template<class T>
void set(typename boost::disable_if<boost::is_pod<T>, std::string>::type path, const T data)
{
    std::cout << "Non-POD" << std::endl;
    std::stringstream ss;
    for(typename T::const_iterator it = data.begin(); it < data.end(); ++it)
    {
       ss << *it;
       if(it < data.end() -1 )
          ss << ", ";
    }
    ss << std::endl;
}

int main() {
  int i;
  float f;
  std::vector<int> v;
  set("", v);
  set("", i);
  set("", f);
}

ここでは便宜上ブーストを使用しましたが、ブーストがオプションでない場合は独自にロールするか、代わりにC++11を使用できます。

is_pod本当に望むものではありません。おそらくis_container特性が必要ですが、それはそれほど些細なことではありません。独自の特性を作成し、特性is_pod使用して関数を単純な答えとして選択的に有効にする方法を適切に近似する必要があります。

于 2012-07-19T09:41:02.337 に答える
1

ここで、置換の失敗はエラーではない(SFINAE)手法を試すことができます。

まず、型にイテレータメンバーがあるかどうかを判断する関数が必要です...

template <typename T>
struct Has_Iterator
{
    template <typename>
    static char test(...);

    template <typename U>
    static int test(typename U::const_iterator*);

    static const bool result = sizeof test<T>(0) != sizeof(char);
};

上記のコードでは、実際にメンバータイプを持つ構造体/クラスであるtest(typename U::const_iterator*)限り、あいまいな「...」パラメータの一致よりもC++標準を使用する必要があります。そうしないと、「置換の失敗」が発生します。これは、コンパイルを停止する致命的なエラーではなく(したがって、SFINAE)、一致する関数を見つけようとする試みは、によって満たされます。2つの関数の戻り値のタイプが異なるため、オペレーターはどちらが一致したかをテストして、ブール値を適切に設定できます。U const_iteratortest(...)sizeofresult

次に、印刷するリクエストを、それらをサポートするテンプレートスペシャライゼーションに転送できます...

template <typename T>
void print(const T& data)
{
    printer<Has_Iterator<T>::result, T>()(data);
}

// general case handles types having iterators...
template <bool Has_It, typename T>
struct printer
{
    void operator()(const T& data)
    {
        for (typename T::const_iterator i = data.begin(); i != data.end(); ++i)
            std::cout << *i << ' ';
        std::cout << '\n';
    }
};

// specialisation for types lacking iterators...
template <typename T>
struct printer<false, T>
{
    void operator()(const T& data)
    {
        std::cout << data << '\n';
    }
};
于 2012-07-19T10:27:10.263 に答える
0

私の前任者が書いたように、あなたはある種の特性を使わなければなりません。そのためにはおそらくBoostを使用する必要がありますが、使用したくない場合は、次のようなものを使用できます(http://ideone.com/7mAiB):

template <typename T>
struct has_const_iterator {
    typedef char yes[1];
    typedef char no[2];

    template <typename C> static yes& test(typename C::const_iterator*);
    template <typename> static no& test(...);

    static const bool value = sizeof(test<T>(0)) == sizeof(yes);
};

template <bool> class bool2class {};

template <class T>
void set_inner(const std::string &path, T & var, bool2class<false> *) {
        // T is probably not STL container
}

template <class T>
void set_inner(const std::string &path, T & var, bool2class<true> *) {
        // T is STL container
}

template <class T>
void set(const std::string &path, T &var) {
        set_inner(path, var, (bool2class<has_const_iterator<T>::value>*)0);
}

コンテナと単純な配列を区別するのは簡単な作業ではないので、ここではtypeに。があるかどうかを確認するために使用しましたconst_iterator。おそらく、それが含まれているかどうかbegin()end()および将来のコードで使用するその他のものも確認する必要があります。

于 2012-07-19T10:07:09.970 に答える