定义功能模板

时间:2013-11-29 10:36:41

标签: c++ templates

我想知道下面示例中的cT::value_type表达式对编译器有什么影响?我可以写一个watever,我不会忘记单词value_type - 无论如何它都会构建。看起来代码试图告诉编译器' cT类型应该有一些属性(可能是向量成员,但在模板定义中不可见)该类型将用于第二个函数参数'。我对现实的理解有多远?

编译器如何知道两个参数都应该被视为字符串:

joinContainer(s1, ':'); 

在编译器的地方我会期待像

这样的东西
joinContainer<string,string>(s1, ':'); 

或事件可能

<string>joinContainer<string,string>(s1, ':'); 

整个代码:

// join.cpp by Bill Weinman <http://bw.org/>
#include <iostream>
#include <vector>
using namespace std;

template<typename cT, typename retT = cT, typename sepT = decltype(cT::value_type)>
retT joinContainer(const cT & o, const sepT & sep) {
    retT out;

    auto it = o.begin();
    while(it != o.end())
    {
        out += *it;
        if(++it != o.end()) out += sep;
    }
    return out;
}

int main( int argc, char ** argv ) {
    string s1("This is a string");
    string s2("This is also a string");
    string s3("Yet another string");

    // join the characters of a string


    cout << joinContainer<string, string>(s1, ':') << endl;

    // join strings from a vector, returning a string
    vector<string> vs({s1, s2, s3});
    cout << joinContainer<vector<string>, string>(vs, ", ");
    return 0;
}

2 个答案:

答案 0 :(得分:0)

编译器从2. function参数获取sepT模板参数,因此它可能永远不会使用默认参数(cT::value_type)。因此,它可能永远不会实例化使用第三个模板参数的默认值的模板。

至于你的第二个问题,为什么你可以写joinContainer(s1, ':');并且它有效。编译器具有所需的所有信息。 1.和3.模板参数是从函数参数推导出来的。 2.模板参数未指定,但在定义中有一个默认参数,因此编译器使用它。

joinContainer(s1, ':'); 
cT - type std::string (deduced from s1)
retT - type std::string (default value used, which is the same as cT)
sepT - type const char (deduced from ':')

joinContainer<string,string>(s1, ':'); 
cT - type std::string (because you specified in the template parameters)
retT - type std::string (because you specified in the template parameters)
sepT - type const char (deduced from ':')
note: if s1 would not be of type std::string there would be a compiler error

<string>joinContainer<string,string>(s1, ':'); 
Will not compile.

答案 1 :(得分:0)

这个例子看起来有点不合逻辑。基本上就是这样:

template<typename T = Foo>
void f(const T & x)
{
    // print x, whatever...
}

(“typename T = Foo”与“typename sepT = decltype(cT::value_type)”类似,“const T & x”类似于“const sepT & sep”。

现在,有多少种方法可以调用此功能?只有一个:

    f(obj); // whatever type obj is

也就是说,您必须始终传递参数,并且始终会推导出T,因此永远不会使用Foo

(好的,您也可以强制使用模板参数,例如f<Bar>(obj);,但Foo仍然不会被使用,您也不应该这样做。)

更合乎逻辑的例子是:

template<typename T = Foo>
void g(const T & x = T())
{
    // print x, whatever...
}

现在,由于模板参数的默认值(类型)和函数参数的默认值,您可以使用或不使用参数调用它:

    g(obj);
    g();    // equivalent to g(Foo());

在无参数调用中,使用Foo的默认T


此外,“decltype(cT::value_type)无效decltype采用表达式,而不是类型。也许作者的意思是typename sepT = typename cT::value_type(需要额外的“typename”)。