mirror of
https://github.com/changkun/modern-cpp-tutorial.git
synced 2025-12-17 04:34:40 +03:00
revision #1: 更新第二章中已维护的代码
This commit is contained in:
3
.gitignore
vendored
3
.gitignore
vendored
@@ -27,3 +27,6 @@
|
||||
*.exe
|
||||
*.out
|
||||
*.app
|
||||
|
||||
node_modules
|
||||
website/public
|
||||
@@ -2,7 +2,7 @@
|
||||
// 1.1.cpp
|
||||
//
|
||||
// chapter 1 introduction
|
||||
// c++1x tutorial
|
||||
// modern cpp tutorial
|
||||
//
|
||||
// created by changkun at changkun.de
|
||||
//
|
||||
@@ -12,7 +12,7 @@
|
||||
#include <functional>
|
||||
|
||||
int main() {
|
||||
// 使用 lambda 表达式
|
||||
// use lambda expression
|
||||
[out = std::ref(std::cout << "Result from C code: " << add(1, 2))](){
|
||||
out.get() << ".\n";
|
||||
}();
|
||||
@@ -2,21 +2,21 @@
|
||||
# 1.1.cpp
|
||||
#
|
||||
# chapter 1 introduction
|
||||
# c++1x tutorial
|
||||
# modern cpp tutorial
|
||||
#
|
||||
# created by changkun at changkun.de
|
||||
#
|
||||
|
||||
C = gcc
|
||||
CXX = g++
|
||||
CXX = clang++
|
||||
|
||||
SOURCE_C = foo.c
|
||||
OBJECTS_C = foo.o
|
||||
|
||||
SOURCE_CXX = 1.1.cpp
|
||||
SOURCE_CXX = 1.1.c.and.cpp
|
||||
|
||||
TARGET = 1.1
|
||||
LDFLAGS_COMMON = -std=c++1z
|
||||
TARGET = 1.1.out
|
||||
LDFLAGS_COMMON = -std=c++17
|
||||
|
||||
all:
|
||||
$(C) -c $(SOURCE_C)
|
||||
|
||||
@@ -2,14 +2,14 @@
|
||||
// foo.c
|
||||
//
|
||||
// chapter 1 introduction
|
||||
// c++1x tutorial
|
||||
// modern cpp tutorial
|
||||
//
|
||||
// created by changkun at changkun.de
|
||||
//
|
||||
|
||||
#include "foo.h"
|
||||
|
||||
// C 语言代码
|
||||
// C code
|
||||
int add(int x, int y) {
|
||||
return x+y;
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
// foo.h
|
||||
//
|
||||
// chapter 1 introduction
|
||||
// c++1x tutorial
|
||||
// modern cpp tutorial
|
||||
//
|
||||
// created by changkun at changkun.de
|
||||
//
|
||||
|
||||
@@ -1,32 +0,0 @@
|
||||
//
|
||||
// 2.1.cpp
|
||||
// c++1x tutorial
|
||||
//
|
||||
// created by changkun at changkun.de
|
||||
//
|
||||
// nullptr
|
||||
|
||||
#include <iostream>
|
||||
|
||||
void foo(char *);
|
||||
void foo(int);
|
||||
|
||||
int main() {
|
||||
|
||||
if(NULL == (void *)0)
|
||||
std::cout << "NULL == 0" << std::endl; // 该行将输出
|
||||
else
|
||||
std::cout << "NULL != 0" << std::endl;
|
||||
|
||||
foo(0); // 调用 foo(int)
|
||||
//foo(NULL); // 该行不能通过编译
|
||||
foo(nullptr); // 调用 foo(char*)
|
||||
|
||||
return 0;
|
||||
}
|
||||
void foo(char *ch) {
|
||||
std::cout << "call foo(char*)" << std::endl;
|
||||
}
|
||||
void foo(int i) {
|
||||
std::cout << "call foo(int)" << std::endl;
|
||||
}
|
||||
34
code/2/2.1.nullptr.cpp
Normal file
34
code/2/2.1.nullptr.cpp
Normal file
@@ -0,0 +1,34 @@
|
||||
//
|
||||
// 2.1.nullptr.cpp
|
||||
// chapter 2 language usability
|
||||
// modern cpp tutorial
|
||||
//
|
||||
// created by changkun at changkun.de
|
||||
//
|
||||
|
||||
#include <iostream>
|
||||
#include <type_traits>
|
||||
|
||||
void foo(char *);
|
||||
void foo(int);
|
||||
|
||||
int main() {
|
||||
if (std::is_same<decltype(NULL), decltype(0)>::value)
|
||||
std::cout << "NULL == 0" << std::endl;
|
||||
if (std::is_same<decltype(NULL), decltype((void*)0)>::value)
|
||||
std::cout << "NULL == (void *)0" << std::endl;
|
||||
if (std::is_same<decltype(NULL), std::nullptr_t>::value)
|
||||
std::cout << "NULL == nullptr" << std::endl;
|
||||
|
||||
foo(0); // will call foo(int)
|
||||
// foo(NULL); // doen't compile
|
||||
foo(nullptr); // will call foo(char*)
|
||||
return 0;
|
||||
}
|
||||
|
||||
void foo(char *) {
|
||||
std::cout << "foo(char*) is called" << std::endl;
|
||||
}
|
||||
void foo(int i) {
|
||||
std::cout << "foo(int) is called" << std::endl;
|
||||
}
|
||||
31
code/2/2.10.if.constexpr.cpp
Normal file
31
code/2/2.10.if.constexpr.cpp
Normal file
@@ -0,0 +1,31 @@
|
||||
//
|
||||
// 2.10.if.constexpr.cpp
|
||||
// chapter 2 language usability
|
||||
// modern cpp tutorial
|
||||
//
|
||||
// created by changkun at changkun.de
|
||||
//
|
||||
|
||||
#include <iostream>
|
||||
|
||||
template<typename T>
|
||||
auto print_type_info(const T& t) {
|
||||
if constexpr (std::is_integral<T>::value) {
|
||||
return t + 1;
|
||||
} else {
|
||||
return t + 0.001;
|
||||
}
|
||||
}
|
||||
|
||||
// at compiling time
|
||||
// int print_type_info(const int& t) {
|
||||
// return t + 1;
|
||||
// }
|
||||
// double print_type_info(const double& t) {
|
||||
// return t + 0.001;
|
||||
// }
|
||||
|
||||
int main() {
|
||||
std::cout << print_type_info(5) << std::endl;
|
||||
std::cout << print_type_info(3.14) << std::endl;
|
||||
}
|
||||
23
code/2/2.11.for.loop.cpp
Normal file
23
code/2/2.11.for.loop.cpp
Normal file
@@ -0,0 +1,23 @@
|
||||
//
|
||||
// 2.11.for.loop.cpp
|
||||
// chapter 2 language usability
|
||||
// modern cpp tutorial
|
||||
//
|
||||
// created by changkun at changkun.de
|
||||
//
|
||||
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
#include <algorithm>
|
||||
|
||||
int main() {
|
||||
std::vector<int> vec = {1, 2, 3, 4};
|
||||
if (auto itr = std::find(vec.begin(), vec.end(), 3); itr != vec.end()) *itr = 4;
|
||||
for (auto element : vec)
|
||||
std::cout << element << std::endl; // read only
|
||||
for (auto &element : vec) {
|
||||
element += 1; // writeable
|
||||
}
|
||||
for (auto element : vec)
|
||||
std::cout << element << std::endl; // read only
|
||||
}
|
||||
50
code/2/2.2.constexpr.cpp
Normal file
50
code/2/2.2.constexpr.cpp
Normal file
@@ -0,0 +1,50 @@
|
||||
//
|
||||
// 2.2.constexpr.cpp
|
||||
// chapter 2 language usability
|
||||
// modern cpp tutorial
|
||||
//
|
||||
// created by changkun at changkun.de
|
||||
//
|
||||
|
||||
#include <iostream>
|
||||
#define LEN 10
|
||||
|
||||
int len_foo() {
|
||||
int i = 2;
|
||||
return i;
|
||||
}
|
||||
constexpr int len_foo_constexpr() {
|
||||
return 5;
|
||||
}
|
||||
|
||||
// error in c++11
|
||||
// constexpr int fibonacci(const int n) {
|
||||
// if(n == 1) return 1;
|
||||
// if(n == 2) return 1;
|
||||
// return fibonacci(n-1) + fibonacci(n-2);
|
||||
// }
|
||||
|
||||
// ok
|
||||
constexpr int fibonacci(const int n) {
|
||||
return n == 1 || n == 2 ? 1 : fibonacci(n-1) + fibonacci(n-2);
|
||||
}
|
||||
|
||||
|
||||
int main() {
|
||||
char arr_1[10]; // legal
|
||||
char arr_2[LEN]; // legal
|
||||
|
||||
int len = 10;
|
||||
// char arr_3[len]; // illegal
|
||||
|
||||
const int len_2 = len + 1;
|
||||
char arr_4[len_2]; // legal
|
||||
|
||||
// char arr_5[len_foo()+5]; // illegal
|
||||
char arr_6[len_foo_constexpr() + 1]; // legal
|
||||
|
||||
// 1, 1, 2, 3, 5, 8, 13, 21, 34, 55
|
||||
std::cout << fibonacci(10) << std::endl;
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1,34 +0,0 @@
|
||||
//
|
||||
// 2.2.cpp
|
||||
// c++1x tutorial
|
||||
//
|
||||
// created by changkun at changkun.de
|
||||
//
|
||||
// constexpr
|
||||
|
||||
#include <iostream>
|
||||
#define LEN 10
|
||||
|
||||
constexpr int len_foo() {
|
||||
return 5;
|
||||
}
|
||||
|
||||
constexpr int fibonacci(const int n) {
|
||||
return n == 1 || n == 2 ? 1 : fibonacci(n-1)+fibonacci(n-2);
|
||||
}
|
||||
|
||||
int main() {
|
||||
char arr_1[10];
|
||||
|
||||
char arr_2[LEN];
|
||||
|
||||
const int len = 10;
|
||||
char arr_3[len];
|
||||
|
||||
char arr_5[len_foo()+5];
|
||||
|
||||
std::cout << fibonacci(10) << std::endl;
|
||||
// 1, 1, 2, 3, 5, 8, 13, 21, 34, 55
|
||||
|
||||
return 0;
|
||||
}
|
||||
31
code/2/2.3.if.switch.cpp
Normal file
31
code/2/2.3.if.switch.cpp
Normal file
@@ -0,0 +1,31 @@
|
||||
//
|
||||
// 2.3.if.switch.cpp
|
||||
// chapter 2 language usability
|
||||
// modern cpp tutorial
|
||||
//
|
||||
// created by changkun at changkun.de
|
||||
//
|
||||
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
#include <algorithm>
|
||||
|
||||
int main() {
|
||||
std::vector<int> vec = {1, 2, 3, 4};
|
||||
|
||||
// before c++17, can be simplefied by using `auto`
|
||||
const std::vector<int>::iterator itr = std::find(vec.begin(), vec.end(), 2);
|
||||
if (itr != vec.end()) {
|
||||
*itr = 3;
|
||||
}
|
||||
|
||||
// after c++17, can be simplefied by using `auto`
|
||||
if (const std::vector<int>::iterator itr = std::find(vec.begin(), vec.end(), 3);
|
||||
itr != vec.end()) {
|
||||
*itr = 4;
|
||||
}
|
||||
|
||||
// should output: 1, 4, 3, 4. can be simplefied using `auto`
|
||||
for (std::vector<int>::iterator element = vec.begin(); element != vec.end(); ++element)
|
||||
std::cout << *element << std::endl;
|
||||
}
|
||||
59
code/2/2.4.initializer.list.cpp
Normal file
59
code/2/2.4.initializer.list.cpp
Normal file
@@ -0,0 +1,59 @@
|
||||
//
|
||||
// 2.4.initializer.list.cpp
|
||||
// chapter 2 language usability
|
||||
// modern cpp tutorial
|
||||
//
|
||||
// created by changkun at changkun.de
|
||||
//
|
||||
|
||||
#include <iostream>
|
||||
#include <initializer_list>
|
||||
#include <vector>
|
||||
|
||||
class Foo {
|
||||
public:
|
||||
int value_a;
|
||||
int value_b;
|
||||
Foo(int a, int b) : value_a(a), value_b(b) {}
|
||||
};
|
||||
|
||||
class MagicFoo {
|
||||
public:
|
||||
std::vector<int> vec;
|
||||
MagicFoo(std::initializer_list<int> list) {
|
||||
for (std::initializer_list<int>::iterator it = list.begin(); it != list.end(); ++it) {
|
||||
vec.push_back(*it);
|
||||
}
|
||||
}
|
||||
void foo(std::initializer_list<int> list) {
|
||||
for (std::initializer_list<int>::iterator it = list.begin(); it != list.end(); ++it) {
|
||||
vec.push_back(*it);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
int main() {
|
||||
// before C++11
|
||||
int arr[3] = {1, 2, 3};
|
||||
Foo foo(1, 2);
|
||||
std::vector<int> vec = {1, 2, 3, 4, 5};
|
||||
|
||||
// after C++11
|
||||
MagicFoo magicFoo = {1, 2, 3, 4, 5};
|
||||
magicFoo.foo({6,7,8,9});
|
||||
Foo foo2 {3, 4};
|
||||
|
||||
std::cout << "arr[0]: " << arr[0] << std::endl;
|
||||
std::cout << "foo:" << foo.value_a << ", " << foo.value_b << std::endl;
|
||||
std::cout << "vec: ";
|
||||
for (std::vector<int>::iterator it = vec.begin(); it != vec.end(); ++it) {
|
||||
std::cout << *it << std::endl;
|
||||
}
|
||||
std::cout << "magicFoo: ";
|
||||
for (std::vector<int>::iterator it = magicFoo.vec.begin(); it != magicFoo.vec.end(); ++it) {
|
||||
std::cout << *it << std::endl;
|
||||
}
|
||||
std::cout << "foo2: " << foo2.value_a << ", " << foo2.value_b << std::endl;
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1,34 +0,0 @@
|
||||
//
|
||||
// 2.5.cpp
|
||||
// c++1x tutorial
|
||||
//
|
||||
// created by changkun at changkun.de
|
||||
//
|
||||
// 初始化列表
|
||||
|
||||
|
||||
#include <initializer_list>
|
||||
|
||||
class Foo {
|
||||
private:
|
||||
int value;
|
||||
public:
|
||||
Foo(int) {}
|
||||
};
|
||||
|
||||
class Magic {
|
||||
public:
|
||||
Magic(std::initializer_list<int> list) {}
|
||||
};
|
||||
|
||||
void func(std::initializer_list<int> list) {
|
||||
return;
|
||||
}
|
||||
|
||||
int main() {
|
||||
int arr[3] = {1,2,3}; // 列表初始化
|
||||
Foo foo(1); // 普通构造初始化
|
||||
|
||||
Magic magic = {1,2,3,4,5}; // 使用 initialize_list
|
||||
func({1,2,3});
|
||||
}
|
||||
20
code/2/2.5.structured.binding.cpp
Normal file
20
code/2/2.5.structured.binding.cpp
Normal file
@@ -0,0 +1,20 @@
|
||||
//
|
||||
// 2.5.structured.binding.cpp
|
||||
// chapter 2 language usability
|
||||
// modern cpp tutorial
|
||||
//
|
||||
// created by changkun at changkun.de
|
||||
//
|
||||
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
|
||||
std::tuple<int, double, std::string> f() {
|
||||
return std::make_tuple(1, 2.3, "456");
|
||||
}
|
||||
|
||||
int main() {
|
||||
auto [x, y, z] = f();
|
||||
std::cout << x << ", " << y << ", " << z << std::endl;
|
||||
return 0;
|
||||
}
|
||||
42
code/2/2.6.auto.cpp
Normal file
42
code/2/2.6.auto.cpp
Normal file
@@ -0,0 +1,42 @@
|
||||
//
|
||||
// 2.6.auto.cpp
|
||||
// chapter 2 language usability
|
||||
// modern cpp tutorial
|
||||
//
|
||||
// created by changkun at changkun.de
|
||||
//
|
||||
|
||||
#include <initializer_list>
|
||||
#include <vector>
|
||||
#include <iostream>
|
||||
|
||||
class MagicFoo {
|
||||
public:
|
||||
std::vector<int> vec;
|
||||
MagicFoo(std::initializer_list<int> list) {
|
||||
for (auto it = list.begin(); it != list.end(); ++it) {
|
||||
vec.push_back(*it);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// wrong
|
||||
// int add(auto x, auto y) {
|
||||
// return x+y;
|
||||
// }
|
||||
|
||||
int main() {
|
||||
MagicFoo magicFoo = {1, 2, 3, 4, 5};
|
||||
std::cout << "magicFoo: ";
|
||||
for (auto it = magicFoo.vec.begin(); it != magicFoo.vec.end(); ++it) {
|
||||
std::cout << *it << ", ";
|
||||
}
|
||||
std::cout << std::endl;
|
||||
|
||||
auto i = 5; // type int
|
||||
auto j = 6; // type int
|
||||
auto arr = new auto(10); // type int*
|
||||
// auto auto_arr2[10] = arr;
|
||||
// std::cout << add(i, j) << std::endl;
|
||||
return 0;
|
||||
}
|
||||
23
code/2/2.7.decltype.cpp
Normal file
23
code/2/2.7.decltype.cpp
Normal file
@@ -0,0 +1,23 @@
|
||||
//
|
||||
// 2.7.decltype.cpp
|
||||
// chapter 2 language usability
|
||||
// modern cpp tutorial
|
||||
//
|
||||
// created by changkun at changkun.de
|
||||
//
|
||||
|
||||
#include <iostream>
|
||||
#include <type_traits>
|
||||
|
||||
int main() {
|
||||
auto x = 1;
|
||||
auto y = 2;
|
||||
decltype(x+y) z = 3;
|
||||
if (std::is_same<decltype(x), int>::value)
|
||||
std::cout << "type x == int" << std::endl;
|
||||
if (std::is_same<decltype(x), float>::value)
|
||||
std::cout << "type z == float" << std::endl;
|
||||
if (std::is_same<decltype(x), decltype(z)>::value)
|
||||
std::cout << "type z == type x" << std::endl;
|
||||
return 0;
|
||||
}
|
||||
46
code/2/2.8.tail.return.type.cpp
Normal file
46
code/2/2.8.tail.return.type.cpp
Normal file
@@ -0,0 +1,46 @@
|
||||
//
|
||||
// 2.8.tail.return.type.cpp
|
||||
// chapter 2 language usability
|
||||
// modern cpp tutorial
|
||||
//
|
||||
// created by changkun at changkun.de
|
||||
//
|
||||
|
||||
#include <iostream>
|
||||
#include <type_traits>
|
||||
|
||||
// before c++11
|
||||
template<typename R, typename T, typename U>
|
||||
R add(T x, U y) {
|
||||
return x + y;
|
||||
}
|
||||
// after c++11
|
||||
template<typename T, typename U>
|
||||
auto add2(T x, U y) -> decltype(x+y){
|
||||
return x + y;
|
||||
}
|
||||
// after c++14
|
||||
template<typename T, typename U>
|
||||
auto add3(T x, U y){
|
||||
return x + y;
|
||||
}
|
||||
|
||||
int main() {
|
||||
|
||||
// before c++11
|
||||
int z = add<int, int, int>(1, 2);
|
||||
std::cout << z << std::endl;
|
||||
|
||||
// after c++11
|
||||
auto w = add2<int, double>(1, 2.0);
|
||||
if (std::is_same<decltype(w), double>::value) {
|
||||
std::cout << "w is double: ";
|
||||
}
|
||||
std::cout << w << std::endl;
|
||||
|
||||
// after c++14
|
||||
auto q = add3<double, int>(1.0, 2);
|
||||
std::cout << "q: " << q << std::endl;
|
||||
|
||||
return 0;
|
||||
}
|
||||
21
code/2/2.9.decltype.auto.cpp
Normal file
21
code/2/2.9.decltype.auto.cpp
Normal file
@@ -0,0 +1,21 @@
|
||||
//
|
||||
// 2.9.decltype.auto.cpp
|
||||
// chapter 2 language usability
|
||||
// modern cpp tutorial
|
||||
//
|
||||
// created by changkun at changkun.de
|
||||
//
|
||||
|
||||
template<int i>
|
||||
struct Int {};
|
||||
|
||||
constexpr auto iter(Int<0>) -> Int<0>;
|
||||
|
||||
template<int i>
|
||||
constexpr auto iter(Int<i>) {
|
||||
return iter(Int<i-1>{});
|
||||
}
|
||||
|
||||
int main() {
|
||||
decltype(iter(Int<10>{})) a;
|
||||
}
|
||||
7
code/2/Makefile
Normal file
7
code/2/Makefile
Normal file
@@ -0,0 +1,7 @@
|
||||
all: $(patsubst %.cpp, %.out, $(wildcard *.cpp))
|
||||
|
||||
%.out: %.cpp Makefile
|
||||
clang++ $< -o $@ -std=c++17
|
||||
|
||||
clean:
|
||||
rm *.out
|
||||
@@ -32,7 +32,7 @@ int main() {
|
||||
|
||||
int arr[10] = {0};
|
||||
auto auto_arr = arr; // 正确,对整个类型进行推导
|
||||
//auto auto_arr2[10] = arr; // 错误, 无法推导数组元素类型
|
||||
// auto auto_arr2[10] = arr; // 错误, 无法推导数组元素类型
|
||||
|
||||
auto x = 1;
|
||||
auto y = 2;
|
||||
21
code/2/todo/2.xxx.cpp
Normal file
21
code/2/todo/2.xxx.cpp
Normal file
@@ -0,0 +1,21 @@
|
||||
#include <iostream>
|
||||
|
||||
template<typename T0>
|
||||
void printf(T0 value) {
|
||||
std::cout << value << std::endl;
|
||||
}
|
||||
template<typename T, typename... Args>
|
||||
void printf(T value, Args... args) {
|
||||
std::cout << value << std::endl;
|
||||
printf(args...);
|
||||
}
|
||||
|
||||
template<typename T0, typename... T>
|
||||
void printf_short(T0 t0, T... t) {
|
||||
std::cout << t0 << std::endl;
|
||||
if constexpr (sizeof...(t) > 0) printf(t...);
|
||||
}
|
||||
int main() {
|
||||
printf_short(1, 2, "123", 1.1);
|
||||
return 0;
|
||||
}
|
||||
8
code/2/todo/fold.expression.cpp
Normal file
8
code/2/todo/fold.expression.cpp
Normal file
@@ -0,0 +1,8 @@
|
||||
#include <iostream>
|
||||
template<typename ... T>
|
||||
auto sum(T ... t) {
|
||||
return (t + ...);
|
||||
}
|
||||
int main() {
|
||||
std::cout << sum(1, 2, 3, 4, 5, 6, 7, 8, 9, 10) << std::endl;
|
||||
}
|
||||
8
exercises/2/fold.expresion.cpp
Normal file
8
exercises/2/fold.expresion.cpp
Normal file
@@ -0,0 +1,8 @@
|
||||
#include <iostream>
|
||||
template<typename ... T>
|
||||
auto average(T ... t) {
|
||||
return (t + ... ) / sizeof...(t);
|
||||
}
|
||||
int main() {
|
||||
std::cout << average(1, 2, 3, 4, 5, 6, 7, 8, 9, 10) << std::endl;
|
||||
}
|
||||
22
exercises/2/structured.binding.cpp
Normal file
22
exercises/2/structured.binding.cpp
Normal file
@@ -0,0 +1,22 @@
|
||||
#include <iostream>
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <functional>
|
||||
|
||||
template <typename Key, typename Value, typename F>
|
||||
void update(std::map<Key, Value>& m, F foo) {
|
||||
for (auto&& [key, value] : m ) value = foo(key);
|
||||
}
|
||||
|
||||
int main() {
|
||||
std::map<std::string, long long int> m {
|
||||
{"a", 1},
|
||||
{"b", 2},
|
||||
{"c", 3}
|
||||
};
|
||||
update(m, [](std::string key) -> long long int {
|
||||
return std::hash<std::string>{}(key);
|
||||
});
|
||||
for (auto&& [key, value] : m)
|
||||
std::cout << key << ":" << value << std::endl;
|
||||
}
|
||||
0
exercises/2/variadic.template.parameter.pack.cpp
Normal file
0
exercises/2/variadic.template.parameter.pack.cpp
Normal file
Reference in New Issue
Block a user