计数算法和指针类型

counting algorithm and pointer types

我编写了以下代码作为有关函数模板和模板特化的练习。它是一个函数,用于计算 vector:

中存在给定类型的对象的数量
template <typename T>
int function(const std::vector<T> &vec, T val) {
    int count = 0;
    for(typename std::vector<T>::const_iterator it = vec.begin(); it != vec.end(); ++it)
        if(*it == val)
            ++count;
    return count;
}

template <>
int function(const std::vector<const char*> &vec, const char* val) {
    int count = 0;
    for(std::vector<const char*>::const_iterator it = vec.begin(); it != vec.end(); ++it) {
        if (std::string(*it) == std::string(val))
            ++count;
    }
    return count;
}

我写专业化的代码是因为我想知道一个单词中的每个字符是否都与给定的文字相同。令我惊讶的是,如果我注释掉特化并让编译器实例化原始模板,它甚至适用于 const char 数组:

int main() {
    std::vector<const char*> cvec = {"hi", "hi", "hallo", "hej", "hej", "hi", "hej", "hej", "hej"};
    std::cout << function(cvec, "hej") << std::endl;
}

Live demo

怎么可能?

I use the code in my main function in order to test it, but, to my surprise, if I comment out the specialization and let the compiler instantiate the original template,it works even for the const char arrays (the type of string literal)! How could it possibly be?


根据 §2.13.5/16,该标准未指定包含相同字符序列的字符串文字必须存储在相同的内存位置:

Evaluating a string-literal results in a string literal object with static storage duration, initialized from the given characters as specified above. Whether all string literals are distinct (that is, are stored in non-overlapping objects) and whether successive evaluations of a string-literal yield the same or a different object is unspecified.

(强调我的)

但是这种实现是允许的,这就是这里发生的事情:每个文字字符串 "hej" 都存储在相同的内存地址中,因此 const char* 上的 == 正在检查地址是否是相同的并且产生 true.


为了"prove"这个我们只需要看一下这个例子:

int main() {
    std::vector<const char*> cvec = {"hi", "hi", "hallo", "hej", "hej", "hi", "hej", "hej", "hej"};
    std::cout << function(cvec, "hej") << '\n';
}

Live demo

这会产生 5,因为向量中有 5 个文字 "hej"。但是,如果我们添加另一个 char 数组,在文字中具有完全相同的 chars,我们知道应该有一个不同的地址:

int main() {
    std::string hej = "hej";
    std::vector<const char*> cvec = {"hi", "hi", "hallo", "hej", "hej", "hi", "hej", "hej", "hej", hej.c_str()};
    std::cout << function(cvec, "hej") << std::endl;
}

Live demo

然后我们看到计数没有改变。