简体   繁体   English

C ++如何区分容器模板和本机类型

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

I have the following problem: 我有以下问题:

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

I get the following error: 我收到以下错误:

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

Is there a way to differentiate between container types and other types in templates? 有没有办法在模板中区分容器类型和其他类型?

Use a trait: 使用特征:

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

You can find a suitable trait in the pretty printer code . 您可以在漂亮的打印机代码中找到合适的特征。

In C++03 you can do this with a little bit of SFINAE to selectively enable different versions of the function for different types: 在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);
}

I used boost for convenience here, but you could roll your own if boost isn't an option or use C++11 instead. 为了方便起见,我在这里使用了boost,但是如果没有选择boost可以使用自己的工具,也可以使用C ++ 11。

is_pod isn't quite what you want really, you probably want an is_container trait, but that's not so trivial, you'll need to make a trait of your own and is_pod makes a good approximation for how to use traits to selectively enable functions as simple answer. is_pod并不是您真正想要的,您可能想要一个is_container特性,但这并不是那么简单,您需要自己创建一个特性,并且is_pod很好地近似了如何使用特性来有选择地启用函数,简单的答案。

You might try Substitution Failure Is Not An Error (SFINAE) techniques here. 您可以在此处尝试“替代失败不是错误(SFINAE)”技术。

Firstly, you need a function to determine whether a type has an iterator member... 首先,您需要一个函数来确定类型是否具有迭代器成员。

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

In the above code, the C++ Standard requires test(typename U::const_iterator*) to be used in preference to the vague "..." parameter match, so long as U is actually a struct/class with a const_iterator member type. 在上面的代码,C ++标准需要test(typename U::const_iterator*)优先于模糊“...”参数匹配中使用,只要U实际上用一个结构/类const_iterator构件类型。 Otherwise, you have a "substitution failure" - which is not a fatal error stopping compilation (hence SFINAE), and the attempt to find a matching function is satified by test(...) . 否则,您将遇到“替换失败”,这不是停止编译的致命错误(因此为SFINAE),而test(...)满足了寻找匹配函数的尝试。 As the return types of the two functions differ, the sizeof operator can test which one has been matched, setting the result boolean appropriately. 由于这两个函数的返回类型不同,因此sizeof运算符可以测试哪个已匹配,并适当地将result设置为布尔值。

Then you can forward requests to print things to template specialisations that support them... 然后,您可以将打印内容的请求转发到支持它们的模板专业领域。

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

As my predecessors wrote you have to use some kind of trait. 正如我的前任所写,您必须使用某种特质。 You probably should use Boost for that, but if you don't want to you can just use something like this ( http://ideone.com/7mAiB ): 您可能应该使用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);
}

It's not an easy task to distinguish container from simple array, so I used here checking if type has const_iterator . 区分容器和简单数组不是一件容易的事,因此我在这里使用检查类型是否具有const_iterator Probably you should also check if it has begin() , end() and other things you would use in future code. 也许您还应该检查它是否具有begin()end()以及将来在代码中要使用的其他内容。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM