百度空间 | 百度首页 
 
查看文章
 
【翻译】VC10中的C++0x新特性:Lambda表达式、auto关键字和static_assert
2009年11月06日 星期五 下午 02:37

零度の冰翻译,点击进入原文,转载请注明出处

Visual Studio 2010(下称VS2010)中的Visual C++编译器包含了对4项(正式发布后可能更多)C++0x 特性的支持,分别为lambda表达式auto关键字static_assert,和右值引用(rvalue references)。此篇文章将对前三项进行详细解释,rvalue references将在后续文章中解释。

相关资料:
C++0x language feature status:
http://open-std.org/JTC1/SC22/WG21/docs/papers/2008/n2705.html
C++0x library feature status:
http://open-std.org/JTC1/SC22/WG21/docs/papers/2008/n2706.html
C++0x Working Draft:
http://open-std.org/JTC1/SC22/WG21/docs/papers/2008/n2798.pdf

Lambda表达式

在C++0x中“lambda表达式”隐式的定义并构造了一个匿名的函数对象,它和普通的函数对象的行为是类似的。下面是“Hello World”的lambda:

C:\Temp>type meow.cpp
#include <algorithm>
#include <iostream>
#include <ostream>
#include <vector>
using namespace std;

int main() {
    vector v;
    for (int i = 0; i < 10; ++i) {
        v.push_back(i);
    }
    for_each(v.begin(), v.end(), [](int n) { cout << n << " "; });
    cout << endl;
}

C:\Temp>cl /EHsc /nologo /W4 meow.cpp > NUL && meow
0 1 2 3 4 5 6 7 8 9

代码中的“[]”叫做“lambda前导符”,它告诉编译器一个lambda表达式开始了。而“(int n)”是lambda表达式中的参数声明部分,它告诉编译器,这个匿名的函数对象中,函数调用运算符(“()”运算符)调用时接受的参数。最后“{ cout << n << " "; }”大括号语句作为这个匿名函数对象的函数调用符的函数体。默认情况下,匿名函数对象的返回值为void。

因此,上面的C++0x代码实质上等价于下面的C++98代码:

C:\Temp>type meow98.cpp
#include <algorithm>
#include <iostream>
#include <ostream>
#include <vector>
using namespace std;

struct LambdaFunctor {
    void operator()(int n) const {
        cout << n << " ";
    }
};

int main() {
    vector v;

    for (int i = 0; i < 10; ++i) {
        v.push_back(i);
    }

    for_each(v.begin(), v.end(), LambdaFunctor());
    cout << endl;
}

C:\Temp>cl /EHsc /nologo /W4 meow98.cpp > NUL && meow98
0 1 2 3 4 5 6 7 8 9

现在,我不再说“那个匿名的函数对象的函数调用运算符的返回值是void”,而是直接说“这个lambda返回void”,但是,非常重要的一点是:一定要记住lambda表达式干了什么:定义了一个类(LambdaFunctor),然后构造了它的对象。

当然了,lambda的大括号表达式中,可以包含多个语句:

C:\Temp>type multimeow.cpp
#include <algorithm>
#include <iostream>
#include <ostream>
#include <vector>
using namespace std;

int main() {
    vector v;

    for (int i = 0; i < 10; ++i) {
        v.push_back(i);
    }

    for_each(v.begin(), v.end(), [](int n) {
        cout << n;

        if (n % 2 == 0) {
            cout << " even ";
        } else {
            cout << " odd ";
        }
    }
);

    cout << endl;
}

C:\Temp>cl /EHsc /nologo /W4 multimeow.cpp > NUL && multimeow
0 even 1 odd 2 even 3 odd 4 even 5 odd 6 even 7 odd 8 even 9 odd

现在,lambda也不必总是返回void,如果一个lambda的大括号表达式为{ return expression; },那么这个lambda的返回值类型将被自动推断为expression的类型:

C:\Temp>type cubicmeow.cpp
#include <algorithm>
#include <deque>
#include <iostream>
#include <iterator>
#include <ostream>
#include <vector>
using namespace std;

int main() {
    vector v;

    for (int i = 0; i < 10; ++i) {
        v.push_back(i);
    }

    deque d;

    transform(v.begin(), v.end(), front_inserter(d), [](int n) { return n * n * n; });

    for_each(d.begin(), d.end(), [](int n) { cout << n << " "; });
    cout << endl;

}

C:\Temp>cl /EHsc /nologo /W4 cubicmeow.cpp > NUL && cubicmeow
729 512 343 216 125 64 27 8 1 0

这里,n * n * n的类型为int,所以,lambda返回值类型为int。

有些更加复杂的lambda表达式无法做出类型推断,你需要显式的指定它:

C:\Temp>type returnmeow.cpp
#include <algorithm>
#include <deque>
#include <iostream>
#include <iterator>
#include <ostream>
#include <vector>
using namespace std;

int main() {
    vector v;

    for (int i = 0; i < 10; ++i) {
        v.push_back(i);
    }

    deque d;

    transform(v.begin(), v.end(), front_inserter(d), [](int n) -> double {
        if (n % 2 == 0) {
            return n * n * n;
        } else {
            return n / 2.0;
        }
    }
);

    for_each(d.begin(), d.end(), [](double x) { cout << x << " "; });
    cout << endl;
}

C:\Temp>cl /EHsc /nologo /W4 returnmeow.cpp > NUL && returnmeow
4.5 512 3.5 216 2.5 64 1.5 8 0.5 0

“-> double”是可选的“lambda返回值类型从句”。为什么返回值类型声明没有像以前声明函数的时候放在前面呢?因为如果不把“[]”放在最前面的话,编译器将无法知道这是一个lambda表达式。

这里,如果你忘记了声明返回值类型,编译器将会报告错误:

C:\Temp>cl /EHsc /nologo /W4 borkedreturnmeow.cpp
borkedreturnmeow.cpp
borkedreturnmeow.cpp(20) : error C3499: a lambda that has been specified to have a void return type cannot return a value
borkedreturnmeow.cpp(22) : error C3499: a lambda that has been specified to have a void return type cannot return a value

上面列出的所有lambda都是无状态的:它们构造出来的匿名函数对象不包含任何数据成员。你也可以获得有状态的lambda,方法是通过“捕获”局部变量。空白的lambda前导符“[]”表示这是一个无状态的lambda,但是在“[]”内部,你可以指定一个捕获组:

C:\Temp>type capturekittybyvalue.cpp
#include <algorithm>
#include <iostream>
#include <ostream>
#include <vector>
using namespace std;

int main() {
    vector v;

    for (int i = 0; i < 10; ++i) {
        v.push_back(i);
    }

    int x = 0;
    int y = 0;

    // op>>()不会读取输入流中最后一个回车换行符,
    // 这有时候会带来很多问题。我推荐
    // 避免使用它,而使用非成员函数
    // getline(cin, str)读取一整行,
    // 然后再解析它。但是为了简洁起见,
    // 我会继续使用 op>>():

    cout << "Input: ";
    cin >> x >> y;

    v.erase(remove_if(v.begin(), v.end(), [x, y](int n) { return x < n && n < y; }), v.end());

    for_each(v.begin(), v.end(), [](int n) { cout << n << " "; });
    cout << endl;
}

C:\Temp>cl /EHsc /nologo /W4 capturekittybyvalue.cpp > NUL && capturekittybyvalue
Input: 4 7
0 1 2 3 4 7 8 9

如果你忘记了写捕获组,编译器会报告错误:

C:\Temp>cl /EHsc /nologo /W4 borkedcapturekittybyvalue.cpp
borkedcapturekittybyvalue.cpp
borkedcapturekittybyvalue.cpp(27) : error C3493: 'x' cannot be implicitly captured as no default capture mode has been specified
borkedcapturekittybyvalue.cpp(27) : error C3493: 'y' cannot be implicitly captured as no default capture mode has been specified

(一会儿我将会介绍默认捕获)

记住,lambda表达式隐式的定义了一个匿名的函数对象,“{ return x < n && n < y; }”就是它函数调用符的函数体,所以尽管看起来大括号语句是在main()的范围内,但在概念上它是在main()函数范围之外的,lambda表达式中不能使用没有捕获的main()函数内的局部变量。

这是把上面程序等价转换后的代码:

C:\Temp>type capturekittybyvalue98.cpp
#include <algorithm>
#include <iostream>
#include <iterator>
#include <ostream>
#include <vector>
using namespace std;

class LambdaFunctor {
public:
    LambdaFunctor(int a, int b) : m_a(a), m_b(b) { }

    bool operator()(int n) const { return m_a < n && n < m_b; }

private:
    int m_a;
    int m_b;
};

int main() {
    vector v;

    for (int i = 0; i < 10; ++i) {
        v.push_back(i);
    }

    int x = 0;
    int y = 0;

    cout << "Input: ";
    cin >> x >> y; // EVIL!

    v.erase(remove_if(v.begin(), v.end(), LambdaFunctor(x, y)), v.end());

    copy(v.begin(), v.end(), ostream_iterator(cout, " "));
    cout << endl;
}

C:\Temp>cl /EHsc /nologo /W4 capturekittybyvalue98.cpp > NUL && capturekittybyvalue98
Input: 4 7
0 1 2 3 4 7 8 9

这里,你可以清楚的看到捕获变量是按值传递的。局部变量的拷贝被存储在了函数对象中。这样,函数对象存活的时间可以比被捕获的局部变量长。但是,需要注意几点:(a)捕获的变量在lambda中不可修改,因为默认情况下生成的是const函数调用运算符;(b)有些对象的复制操作开销比较大;(c)局部变量的更新将不会影响lambda内已经被捕获过的副本(这符合通常的值传递语义)。一会儿,我将解释在需要的时候如何应对上述三种情况。

但是首先,如果你想捕获所有的局部变量,可以不必逐项列出它们,而只需告诉编译器“按值传递捕获所有变量”。实现方式是使用前导符“[=]”:

C:\Temp>type defaultcapturekittybyvalue.cpp
#include <algorithm>
#include <iostream>
#include <ostream>
#include <vector>
using namespace std;

int main() {
    vector v;

    for (int i = 0; i < 10; ++i) {
        v.push_back(i);
    }

    int x = 0;
    int y = 0;

    cout << "Input: ";
    cin >> x >> y; // EVIL!

    v.erase(remove_if(v.begin(), v.end(), [=](int n) { return x < n && n < y; }), v.end());

    for_each(v.begin(), v.end(), [](int n) { cout << n << " "; });
    cout << endl;
}

C:\Temp>cl /EHsc /nologo /W4 defaultcapturekittybyvalue.cpp > NUL && defaultcapturekittybyvalue
Input: 4 7
0 1 2 3 4 7 8 9

当编译器看到lambda中的x和y,会将它们从main()中按值捕获进来。

对于情况(a)无法修改捕获的变量,如何处理呢?默认情况下,lambda的函数调用运算符是const的,但是你可以通过mutable关键字将其变为非const:

C:\Temp>type capturekittybymutablevalue.cpp
#include <algorithm>
#include <iostream>
#include <ostream>
#include <vector>
using namespace std;

int main() {
    vector v;

    for (int i = 0; i < 10; ++i) {
        v.push_back(i);
    }

    int x = 1;
    int y = 1;

    for_each(v.begin(), v.end(), [=](int& r) mutable {
        const int old = r;

        r *= x * y;

        x = y;
        y = old;
    }
);

    for_each(v.begin(), v.end(), [](int n) { cout << n << " "; });
    cout << endl;

    cout << x << ", " << y << endl;
}

C:\Temp>cl /EHsc /nologo /W4 capturekittybymutablevalue.cpp > NUL && capturekittybymutablevalue
0 0 0 6 24 60 120 210 336 504
1, 1

上面代码将v中每个变量变为自身和它前两个变量相乘的结果。注意,(d)对捕获过的变量操作不会影响到原来变量本身(又是通常的值传递语义)。

如果你想对付(b),(c),(d)的话:使用引用传递。方法是在前导符中这样写捕获组:“[&x, &y]”:

C:\Temp>type capturekittybyreference.cpp
#include <algorithm>
#include <iostream>
#include <ostream>
#include <vector>
using namespace std;

int main() {
    vector v;

    for (int i = 0; i < 10; ++i) {
        v.push_back(i);
    }

    int x = 1;
    int y = 1;

    for_each(v.begin(), v.end(), [&x, &y](int& r) {
        const int old = r;

        r *= x * y;

        x = y;
        y = old;
    }
);

    for_each(v.begin(), v.end(), [](int n) { cout << n << " "; });
    cout << endl;

    cout << x << ", " << y << endl;
}

C:\Temp>cl /EHsc /nologo /W4 capturekittybyreference.cpp > NUL && capturekittybyreference
0 0 0 6 24 60 120 210 336 504
8, 9

注意capturekittybyreference.cpp中的变化:(1)lambda前导符“[&x, &y]”,(2)mutable消失了,(3)局部变量x, y的值最终变为了8、9,lambda中对它们的修改反映到了表达式外部。

下面是翻译后的等价代码:

C:\Temp>type capturekittybyreference98.cpp
#include <algorithm>
#include <iostream>
#include <iterator>
#include <ostream>
#include <vector>
using namespace std;

#pragma warning(push)
#pragma warning(disable: 4512) // assignment operator could not be generated

class LambdaFunctor {
public:
    LambdaFunctor(int& a, int& b) : m_a(a), m_b(b) { }

    void operator()(int& r) const {
        const int old = r;

        r *= m_a * m_b;

        m_a = m_b;
        m_b = old;
    }

private:
    int& m_a;
    int& m_b;
};

#pragma warning(pop)

int main() {
    vector v;

    for (int i = 0; i < 10; ++i) {
        v.push_back(i);
    }

    int x = 1;
    int y = 1;

    for_each(v.begin(), v.end(), LambdaFunctor(x, y));

    copy(v.begin(), v.end(), ostream_iterator(cout, " "));
    cout << endl;

    cout << x << ", " << y << endl;
}

C:\Temp>cl /EHsc /nologo /W4 capturekittybyreference98.cpp > NUL && capturekittybyreference98
0 0 0 6 24 60 120 210 336 504
8, 9

(当使用lambda的时候,编译会为lambda的定义部分自动关闭C4512号警告)

当你按照引用传递捕获局部变量时,生成的函数对象存储的是局部变量的引用,这样避免了复制,并且允许函数对象观察这些局部变量的变化甚至修改它们的值。(注意当前生成的函数调用运算符仍然是const修饰的,表示函数对象的成员变量不可更改,而引用类型本身就是不能更改的,但我们可以更改它引用的变量。函数调用运算符的常量性仍然得到保持)

当然了,如果一个lambda的函数对象的寿命长于它所引用的局部变量,程序会down掉。

再一次的,你可以使用默认捕获:“[&]”代表“按引用传递捕获所有”。

如何混合值传递捕获和引用传递捕获呢?你可以用“[a, b, c, &d, e, &f, g]”。也可以指定一个默认捕获方式,但对于特殊的变量指定不同的捕获方式:

C:\Temp>type overridekitty.cpp
#include <algorithm>
#include <iostream>
#include <ostream>
#include <vector>
using namespace std;

int main() {
    vector v;

    for (int i = 0; i < 10; ++i) {
        v.push_back(i);
    }

    int sum = 0;
    int product = 1;

    int x = 1;
    int y = 1;

    for_each(v.begin(), v.end(), [=, &sum, &product](int& r) mutable {
        sum += r;

        if (r != 0) {
            product *= r;
        }

        const int old = r;

        r *= x * y;

        x = y;
        y = old;
    }
);

    for_each(v.begin(), v.end(), [](int n) { cout << n << " "; });
    cout << endl;

    cout << "sum: " << sum << ", product: " << product << endl;
    cout << "x: " << x << ", y: " << y << endl;
}

C:\Temp>cl /EHsc /nologo /W4 overridekitty.cpp && overridekitty
overridekitty.cpp
0 0 0 6 24 60 120 210 336 504
sum: 45, product: 362880
x: 1, y: 1

这里我们想按值捕获x, y(因为我们不想让内部对x, y副本的修改影响到他们本身),按引用捕获sum和product(因为我们确实想在lambda内部修改它们本身的值)。使用“[&, x, y]”前导符会导致同样的结果。

接下来,如果你想做下面的事情该怎么办?

C:\Temp>type memberkitty.cpp
#include <algorithm>
#include <iostream>
#include <ostream>
#include <vector>
using namespace std;

class Kitty {
public:
    explicit Kitty(int toys) : m_toys(toys) { }

    void meow(const vector& v) const {
        for_each(v.begin(), v.end(), [m_toys](int n) {
            cout << "If you gave me " << n << " toys, I would have " << n + m_toys << " toys total." << endl;
        }
);
    }

private:
    int m_toys;
};

int main() {
    vector v;

    for (int i = 0; i < 3; ++i) {
        v.push_back(i);
    }

    Kitty k(5);
    k.meow(v);
}

C:\Temp>cl /EHsc /nologo /W4 memberkitty.cpp
memberkitty.cpp
memberkitty.cpp(12) : error C3480: 'Kitty::m_toys': a lambda capture variable must be from an enclosing function scope

lambda表达式允许捕获局部变量,但是数据成员不是局部变量。用一种特殊的方法,你可以捕获“this”:

C:\Temp>type workingmemberkitty.cpp
#include <algorithm>
#include <iostream>
#include <ostream>
#include <vector>
using namespace std;

class Kitty {
public:
    explicit Kitty(int toys) : m_toys(toys) { }

    void meow(const vector& v) const {
        for_each(v.begin(), v.end(), [this](int n) {
            cout << "If you gave me " << n << " toys, I would have " << n + m_toys << " toys total." << endl;
        }
);
    }

private:
    int m_toys;
};

int main() {
    vector v;

    for (int i = 0; i < 3; ++i) {
        v.push_back(i);
    }

    Kitty k(5);
    k.meow(v);
}

C:\Temp>cl /EHsc /nologo /W4 workingmemberkitty.cpp > NUL && workingmemberkitty
If you gave me 0 toys, I would have 5 toys total.
If you gave me 1 toys, I would have 6 toys total.
If you gave me 2 toys, I would have 7 toys total.

当你捕获了this以后,m_toys就可以使用了,它隐式的表示this->m_toys,你也可以显示的说明this->m_toys。(在lambda表达式中,只有捕获了this后才可以使用它,你永远无法得到lambda表达式本身的this指针)

你也可以隐式的捕获this:

C:\Temp>type implicitmemberkitty.cpp
#include <algorithm>
#include <iostream>
#include <ostream>
#include <vector>
using namespace std;

class Kitty {
public:
    explicit Kitty(int toys) : m_toys(toys) { }

    void meow(const vector& v) const {
        for_each(v.begin(), v.end(), [=](int n) {
            cout << "If you gave me " << n << " toys, I would have " << n + m_toys << " toys total." << endl;
        }
);
    }

private:
    int m_toys;
};

int main() {
    vector v;

    for (int i = 0; i < 3; ++i) {
        v.push_back(i);
    }

    Kitty k(5);
    k.meow(v);
}

C:\Temp>cl /EHsc /nologo /W4 implicitmemberkitty.cpp > NUL && implicitmemberkitty
If you gave me 0 toys, I would have 5 toys total.
If you gave me 1 toys, I would have 6 toys total.
If you gave me 2 toys, I would have 7 toys total.

你也可以使用“[&]”,但是它不会影响this的捕获方式(永远按值传递)。“[&this]”是不允许的。

如果你想得到一个空参数的lambda,可以直接省略小括号部分:

C:\Temp>type nullarykitty.cpp
#include <algorithm>
#include <iostream>
#include <iterator>
#include <ostream>
#include <vector>
using namespace std;

int main() {
    vector v;

    int i = 0;

    generate_n(back_inserter(v), 10, [&] { return i++; });

    for_each(v.begin(), v.end(), [](int n) { cout << n << " "; });
    cout << endl;

    cout << "i: " << i << endl;
}

C:\Temp>cl /EHsc /nologo /W4 nullarykitty.cpp > NUL && nullarykitty
0 1 2 3 4 5 6 7 8 9
i: 10

这比“[&]() { return i++; }”少两个字符。到底这么干好不好就得看自己怎么想了。

搞笑的是,这意味这下面代码在C++0x中是有效的:

C:\Temp>type nokitty.cpp
int main() {
    [](){}();
    []{}();
}

上面构造了俩啥也不干的lambda(一个有参数声明,一个没有),然后马上调用它们(最后的那个空的小括号)。

注意语法上可选的lambda参数声明包括:

(参数声明)[可选]mutable[可选]可能抛的异常[可选]lambda返回值类型[可选]

因此,如果要指定mutable或是 -> return type,那么空的()就不能省略。

最后,由于lambda生成的是普通的函数对象,你可以将其存储在 std::tr1::function 里面:

C:\Temp>type tr1kitty.cpp
#include <algorithm>
#include <functional>
#include <iostream>
#include <ostream>
#include <vector>
using namespace std;
using namespace std::tr1;

void meow(const vector& v, const function& f) {
    for_each(v.begin(), v.end(), f);
    cout << endl;
}

int main() {
    vector v;

    for (int i = 0; i < 10; ++i) {
        v.push_back(i);
    }

    meow(v, [](int n) { cout << n << " "; });
    meow(v, [](int n) { cout << n * n << " "; });

    function g = [](int n) { cout << n * n * n << " "; };

    meow(v, g);

}

C:\Temp>cl /EHsc /nologo /W4 tr1kitty.cpp > NUL && tr1kitty
0 1 2 3 4 5 6 7 8 9
0 1 4 9 16 25 36 49 64 81
0 1 8 27 64 125 216 343 512 729

auto

auto关键字在C++98里面就有,但是它实际上没有干什么事。在C++0x中,它被重新定义为类型自动推断。当使用它声明变量的时候,意思是说“把该变量的类型设置为初始化它的那个变量的类型”。

C:\Temp>type autocat.cpp
#include <iostream>
#include <map>
#include <ostream>
#include <regex>
#include <string>
using namespace std;
using namespace std::tr1;

int main() {
    map m;

    const regex r("(\\w+) (\\w+)");

    for (string s; getline(cin, s); ) {
        smatch results;

        if (regex_match(s, results, r)) {
            m[results[1]] = results[2];
        }
    }

    for (auto i = m.begin(); i != m.end(); ++i) {
        cout << i->second << " are " << i->first << endl;
    }
}

C:\Temp>cl /EHsc /nologo /W4 autocat.cpp > NUL && autocat
cute kittens
ugly puppies
evil goblins
^Z
kittens are cute
goblins are evil
puppies are ugly

map::iterator, your decade-long reign of terror has come to an end!

(注意m.begin()返回的是iterator,不是const_iterator,因为map本身不const,C++0x中cbegin()允许从非const容器中请求一个const_iterator。)

lambda和auto

之前提到过将lambda存储在std::tr1::function中。但是尽量不要这么做,因为std::tr1::function块头比较大开销也很大。如果你想复用一个lambda,或者只是想简单的给它命名,你可以使用auto。下面有一个非常简洁的例子:

C:\Temp>type autolambdakitty.cpp
#include <algorithm>
#include <iostream>
#include <ostream>
#include <vector>
using namespace std;

template void keep_if(vector& v, Predicate pred) {
    auto notpred = [&](const T& t) {
        return !pred(t);
    };

    v.erase(remove_if(v.begin(), v.end(), notpred), v.end());
}

template void print(const Container& c) {
    for_each(c.begin(), c.end(), [](const typename Container::value_type& e) { cout << e << " "; });
    cout << endl;
}

int main() {
    vector a;

    for (int i = 0; i < 100; ++i) {
        a.push_back(i);
    }

    vector b;

    for (int i = 100; i < 200; ++i) {
        b.push_back(i);
    }

    auto prime = [](const int n) -> bool {
        if (n < 2) {
            return false;
        }

        for (int i = 2; i <= n / i; ++i) {
            if (n % i == 0) {
                return false;
            }
        }

        return true;
    };

    keep_if(a, prime);
    keep_if(b, prime);

    print(a);
    print(b);
}

C:\Temp>cl /EHsc /nologo /W4 autolambdakitty.cpp
autolambdakitty.cpp

C:\Temp>autolambdakitty
2 3 5 7 11 13 17 19 23 29 31 37 41 43 47 53 59 61 67 71 73 79 83 89 97
101 103 107 109 113 127 131 137 139 149 151 157 163 167 173 179 181 191 193 197 199

notpred是一个否定性质的lambda!注意,我们不能使用C++98里面的not1(),它要求你写的“断定”部分从unary_function中派生,但是lambda不是。

static_assert

static_assert允许你使用自定义的错误消息引发编译错误:

C:\Temp>type staticfluffykitten.cpp
template struct Kitten {
    static_assert(N < 2, "Kitten requires N < 2.");
};

int main() {
    Kitten<1> peppermint;

    Kitten<3> jazz;
}

C:\Temp>cl /EHsc /nologo /W4 staticfluffykitten.cpp
staticfluffykitten.cpp
staticfluffykitten.cpp(2) : error C2338: Kitten requires N < 2.
        staticfluffykitten.cpp(8) : see reference to class template instantiation 'Kitten' being compiled
        with
        [
            N=3
        ]

Stephan T. Lavavej
Visual C++ Libraries Developer

译著:本人纯属一时兴起将此文翻译,错误多多,有问题的同志请留言。


类别:visual c++ | 添加到搜藏 | 浏览() | 评论 (1)
 
最近读者:
 
网友评论:
1
2009年11月11日 星期三 下午 02:53 | 回复
精辟!
把这篇博客文字作为我测试校内日志的测试数据了,谢谢阿
 
发表评论:
姓 名:
网址或邮箱: (选填)
内 容:
验证码: 请点击后输入四位验证码,字母不区分大小写
      

     

©2009 Baidu