我的意思是,除了它的义务名称(标准模板库)......
C++最初的目的是将OOP概念呈现给C.即:您可以基于其类和类层次结构来判断特定实体可以做什么和不可行(不管它是如何做的).由于多重继承的问题,以及C++以某种笨拙的方式支持接口的概念(与java等相比),某些能力组合更难以这种方式描述,但它存在(并且可能是改善).
然后模板与STL一起发挥作用.STL似乎采用了经典的OOP概念,并使用模板代替了它们.
在使用模板来概括类型的情况之间应该有区别,其中类型自身与模板的操作无关(例如,容器).有一个vector<int>完美的感觉.
但是,在许多其他情况下(迭代器和算法),模板化类型应该遵循"概念"(输入迭代器,前向迭代器等等),其中概念的实际细节完全由模板的实现定义函数/类,而不是与模板一起使用的类的类,这是对OOP的一种反对使用.
例如,您可以告诉函数:
void MyFunc(ForwardIterator<...> *I);
Run Code Online (Sandbox Code Playgroud)
更新:由于在原始问题中不清楚,因此ForwardIterator可以自行模板化以允许任何ForwardIterator类型.相反,将ForwardIterator作为一个概念.
只需通过查看其定义来预期转发迭代器,您需要查看实现或文档:
template <typename Type> void MyFunc(Type *I);
Run Code Online (Sandbox Code Playgroud)
我可以支持使用模板的两个声明:通过为每个使用的类型定制编译模板,而不是使用vtable,可以提高编译代码的效率.并且模板可以与本机类型一起使用.
但是,我正在寻找一个更为深刻的理由,为什么放弃传统的OOP而不是模仿STL呢?(假设你读到那么远:P)
我需要检查一个字符串是否包含另一个字符串?
var str1 = "ABCDEFGHIJKLMNOP";
var str2 = "DEFG";
Run Code Online (Sandbox Code Playgroud)
我用哪个函数来确定str1是否包含str2?
请考虑以下代码段:
struct Base { };
struct Derived : Base { };
void f(Base &) { std::cout << "f(Base&)\n"; }
template <class T = int>
void g() {
Derived d;
f(T{} ? d : d); // 1
}
void f(Derived &) { std::cout << "f(Derived&)\n"; }
int main() {
g();
}
Run Code Online (Sandbox Code Playgroud)
在这种情况下,我认为应该在第一阶段查找对fat 的函数调用// 1,因为它的参数的类型是明确的Derived&,因此可以解析为f(Base&)范围中唯一的一个.
Clang 3.8.0同意我的观点,但是GCC 6.1.0没有,并推迟f到第二阶段的查找,在那里f(Derived&)被选中.
哪个编译器是对的?
我有一个带有模板模板参数的类模板,我想将此参数(即其所有特化)声明为friend.但我找不到正确的语法.
template <template <class> class T>
struct Foo {
template <class U>
friend T; // "C++ requires a type specifier for all declarations"
template <class U>
friend struct T; // "declaration of 'T' shadows template parameter"
template <class U>
friend struct T<U>; // "cannot specialize a template template parameter"
pretty<please>
lets(be) friends T; // Compiler shook its standard output in pity
};
Run Code Online (Sandbox Code Playgroud)
如何将模板模板参数声明为friend?
我试图用来std::make_unique实现一个构造函数要接收的类std::initializer_list.这是一个最小的案例:
#include <string>
#include <vector>
#include <initializer_list>
#include <memory>
struct Foo {
Foo(std::initializer_list<std::string> strings) : strings(strings) {}
std::vector<std::string> strings;
};
int main(int, char**) {
auto ptr = std::make_unique<Foo>({"Hello", "World"});
return 0;
}
Run Code Online (Sandbox Code Playgroud)
您可以在Coliru上看到它没有构建:
main.cpp:14:56: error: no matching function for call to 'make_unique(<brace-enclosed initializer list>)'
auto ptr = std::make_unique<Foo>({"Hello", "World"});
Run Code Online (Sandbox Code Playgroud)
那么,make_unique据说无法使用initializer_lists?GCC 4.9.1中有错误吗?或者我忽略了什么?
我在书中遇到过这个:
wscanf(L"%lf", &variable);
Run Code Online (Sandbox Code Playgroud)
其中第一个参数的类型为wchar_t *.
这scanf("%lf", &variable);与第一个参数的类型不同char *.
那有什么不同呢?我之前从未听过"宽字符串".我听过一些名为Raw String Literals的东西,它正在打印字符串(不需要像转义序列那样的东西),但那不是在C.
我知道sizeof永远不会评估它的操作数,除非在所述操作数是VLA的特定情况下.或者,我以为我知道.
void g(int n) {
printf("g(%d)\n", n);
}
int main(void) {
int i = 12;
char arr[i]; // VLA
(void)sizeof *(g(1), &arr); // Prints "g(1)"
(void)sizeof (g(2), arr); // Prints nothing
return 0;
}
Run Code Online (Sandbox Code Playgroud)
到底是怎么回事?
以防万一,这是在Coliru上用GCC 5.1编译的.
怎么find_type知道功能typemap在哪里?
它收到的参数不是来自该命名空间,而是来自std命名空间!
#include <type_traits>
#include <memory>
namespace lib {
template<typename T>
struct find_type {
using type = decltype(typemap(std::declval<T>()));
};
}
namespace test {
struct Test {};
auto typemap(std::unique_ptr<Test>) -> int;
}
static_assert(std::is_same<int, lib::find_type<std::unique_ptr<test::Test>>::type>::value, "");
Run Code Online (Sandbox Code Playgroud)
这段代码怎么样?允许这个的规则是什么?
我用GCC 6.3和clang 3.9.1测试了它.
我认为GCC扩展__attribute__((cleanup))是一个好主意,至少在某些情况下,但我无法弄清楚如何以一种好的方式使用它.我所做的一切看起来仍然很烦人.
我看到了很多的代码做#define _cleanup_(x) __attribute__((cleanup(x))只是为了少打字,但它有没有办法通过有没有一个标准功能一样free或者closedir,fclose等?
我看到我不能写:
__attribute__((cleanup(free))) char *foo = malloc(10);
Run Code Online (Sandbox Code Playgroud)
因为清理回调会收到char**指针,所以我必须总是这样写:
static void free_char(char **ptr) { free(*ptr); }
__cleanup__((free_char)) char *foo = malloc(10);
Run Code Online (Sandbox Code Playgroud)
这非常烦人,最烦人的部分是为你需要的所有类型定义这样的清理函数,因为显然你不能只为它定义它void **.避免这些事情的最佳方法是什么?
在我的编译器上,以下伪代码(用二进制替换的值):
sint32 word = (10000000 00000000 00000000 00000000);
word >>= 16;
Run Code Online (Sandbox Code Playgroud)
生成一个如下所示word的位域:
(11111111 11111111 10000000 00000000)
Run Code Online (Sandbox Code Playgroud)
我的问题是,我可以依赖所有平台和C++编译器的这种行为吗?
c++ ×6
c ×3
string ×2
templates ×2
bit-shift ×1
c++11 ×1
c++14 ×1
clang ×1
comparison ×1
compiler-bug ×1
contains ×1
friend ×1
gcc ×1
javascript ×1
jquery ×1
name-lookup ×1
oop ×1
side-effects ×1
sizeof ×1
stl ×1
unique-ptr ×1
widechar ×1