簡體   English   中英

C ++如何區分容器模板和本機類型

[英]C++ how to differentiate between template for container and native type

我有以下問題:

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)’

有沒有辦法在模板中區分容器類型和其他類型?

使用特征:

#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());
}

您可以在漂亮的打印機代碼中找到合適的特征。

在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);
}

為了方便起見,我在這里使用了boost,但是如果沒有選擇boost可以使用自己的工具,也可以使用C ++ 11。

is_pod並不是您真正想要的,您可能想要一個is_container特性,但這並不是那么簡單,您需要自己創建一個特性,並且is_pod很好地近似了如何使用特性來有選擇地啟用函數,簡單的答案。

您可以在此處嘗試“替代失敗不是錯誤(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);
};

在上面的代碼,C ++標准需要test(typename U::const_iterator*)優先於模糊“...”參數匹配中使用,只要U實際上用一個結構/類const_iterator構件類型。 否則,您將遇到“替換失敗”,這不是停止編譯的致命錯誤(因此為SFINAE),而test(...)滿足了尋找匹配函數的嘗試。 由於這兩個函數的返回類型不同,因此sizeof運算符可以測試哪個已匹配,並適當地將result設置為布爾值。

然后,您可以將打印內容的請求轉發到支持它們的模板專業領域。

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';
    }
};

正如我的前任所寫,您必須使用某種特質。 您可能應該使用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);
}

區分容器和簡單數組不是一件容易的事,因此我在這里使用檢查類型是否具有const_iterator 也許您還應該檢查它是否具有begin()end()以及將來在代碼中要使用的其他內容。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM