std :: string不能与std :: set一起使用

时间:2011-04-08 03:11:55

标签: c++ string set

我正在从C ++ Primer Plus做一个编程问题,要求我制作一个模板 返回数组中唯一元素数的函数。我不明白为什么
根据我的知识编译时,第13行导致错误,std :: string的行为类似于数组。

这是我的代码:

#include <iostream>
#include <set>

template <typename T>
int reduce(T ar[], int n);

int main()
{
    long test[] = {1, 2, 1, 3, 3, 4, 1};
    std::string testStr = "testing";

    std::cout << reduce(test, 6) << std::endl;
    std::cout << reduce(testStr, 7) << std::endl;

    std::cin.get();

    return 0;
}

template <typename T>
int reduce(T ar[], int n)
{
    std::set<T> test;
    for(int i = 0; i < n; i++)
    {
        test.insert(ar[i]);
    }
    return test.size();
}

3 个答案:

答案 0 :(得分:4)

我立即回复std::string不是数组,这就是C ++人员完成你正在寻找的任务的方式。

#include <iterator>
#include <iostream>
#include <set>

// instead of taking an array and length, just take where you want to start and where
// you want to stop.
template <typename TForwardIterator>
int reduce(TForwardIterator iter, TForwardIterator end)
{
    // This is hideous syntax to get the type of object the iterator is describing.
    // For std::string, it is char...for T*, it is T.
    // I apologize for C++, I'm not sure there is a better way to do this.
    typedef typename std::iterator_traits<TForwardIterator>::value_type value_type;
    std::set<value_type> set;

    // instead of forcing the objects to be an array type, use iterators!
    for (; iter != end; ++iter)
        set.insert(*iter);
    return set.size();
}

int main()
{
    long test[] = {1, 2, 1, 3, 3, 4, 1};
    std::string testStr = "testing";

    // begin() and end() are iterators you'll find on all the container types
    std::cout << reduce(testStr.begin(), testStr.end()) << std::endl;
    // pointers are iterators, too!
    std::cout << reduce(test, test + 7) << std::endl;

    return 0;
}

答案 1 :(得分:2)

答案很简单:std::string不是数组。

只要您可以使用[]运算符访问元素,它就像一个数组,但它与char[]的数据类型不同。事实上,该标准甚至不保证它像数组一样存储(意味着连续)。 T[]只会匹配数组,而不是可以使用arraylike的对象。

为了解决这个问题,你有几个选择

  1. 您可以致电reduce(teststr.c_str(), 7),因为c_str()会返回带有字符串内容的字符。
  2. 您可以将reduce重写为template <typename T, typename U> int reduce(U ar, int n),并将其称为reduce<long>(test, 6)reduce<char>(testStr, 7)。第二个模板参数是必需的,因为没有统一的方法从容器到元素(c ++ 0x /使用编译器扩展除外)。
  3. 如果您使用的是c ++ 0x,您可以使用decltype从容器到包含的元素:template <typename T>int reduce(T ar, int n)std::set<decltype(ar[0])> test;(其余代码保持不变,不知怎的,我似乎有代码块部分有问题,所以这里只有这两行。
  4. 当然在c ++中,人们通常会根据迭代器编写这样的函数(参见Travis Gockels的答案),因为这只是一种更灵活,更好的支持方式。

答案 2 :(得分:1)

您可能会将std :: strings与内置字符数组混淆。 std :: strings不是数组,虽然它们的行为与数组类似(该类有一个重载的[]运算符)并且包含数组(可以通过c_str()访问)。

如果用

替换第10行
char testStr[] = "testing";

您的程序将编译并运行。

或者,您可以尝试以下方式:

#include <iostream>
#include <set>

template <typename T>
int reduce(const T* ar, int n);

int main()
{
    long test[] = {1, 2, 1, 3, 3, 4, 1};
    std::string testStr = "testing";

    std::cout << reduce(test, 7) << std::endl;
    std::cout << reduce(testStr.c_str(), testStr.size()) << std::endl;

    std::cin.get();

    return 0;
}

template <typename T>
int reduce (const T* ar, int n)
{
    std::set<T> test;
    for(int i = 0; i < n; i++)
    {
        test.insert(ar[i]);
    }
    return test.size();
}