我对以下代码感到有点困惑:
#include <iostream>
const char* f()
{
const char* arr[]={"test"};
return arr[0];
}
int main()
{
auto x = f();
std::cout << x;
}
Run Code Online (Sandbox Code Playgroud)
在我看来,这段代码应该是UB(未定义的行为).我们返回一个指向本地范围内的C风格数组元素的指针.事情应该出问题.但是,我测试过的编译器都没有抱怨(我用过-Wall -Wextra -pedanticg ++和clang).valgrind也不抱怨.
上面的代码是有效的还是人们会想到的UB?
PS:运行它似乎产生"正确"的结果,即显示"测试",但这并不表示正确性.
我非常清楚为什么需要使用typename依赖类型,因为当它看到类似的东西时,编译器可能无法消除类型和变量声明之间的歧义T::type,请参阅此答案以获得一个很好的解释.TL; DR:在类似的表达式中T::type * x;,编译器不能"知道" T::type是某个类型,还是在某个特定的特化中声明的变量T.
但是,在类似的东西
using type = T::type;
Run Code Online (Sandbox Code Playgroud)
没有任何暧昧.IMO T::type 应该始终被解析为一个类型,因为它是using语句的RHS的一部分.但是,我们仍然需要在typename这里使用(至少根据gcc和clang),
using type = typename T::type;
Run Code Online (Sandbox Code Playgroud)
Live on Coliru, gcc Live on Coliru, clang
Visual C++ 似乎接受了没有a 的代码typename,但是我对编译器完全符合标准没有太多信心(实际上,它有许多非标准扩展,例如将rvalues绑定到非const引用).
问:有什么理由说这不是typenameC++ 11及更高版本规则的例外吗?
考虑一下代码
#include <iostream>
class Foo
{
int val_;
public:
Foo(std::initializer_list<Foo> il)
{
std::cout << "initializer_list ctor" << std::endl;
}
/* explicit */ Foo(int val): val_(val)
{
std::cout << "ctor" << std::endl;
};
};
int main(int argc, char const *argv[])
{
// why is the initializer_list ctor invoked?
Foo foo {10};
}
Run Code Online (Sandbox Code Playgroud)
输出是
ctor
initializer_list ctor
Run Code Online (Sandbox Code Playgroud)
据我所知,该值10被隐式转换为Foo(第一个ctor输出),然后初始化构造函数启动(第二个initializer_list ctor输出).我的问题是为什么会发生这种情况?标准构造函数Foo(int)不是更好的匹配吗?也就是说,我本来希望这个片段的输出是公正的ctor.
PS:如果我将构造函数标记Foo(int)为explicit,则Foo(int)调用唯一的构造函数,因为整数10现在不能隐式转换为a Foo.
我试图了解它是如何std::declval<T>()工作的.我知道如何使用它,并知道它的作用,主要是允许你在decltype不构造对象的情况下使用,比如
decltype(std::declval<Foo>().some_func()) my_type; // no construction of Foo
Run Code Online (Sandbox Code Playgroud)
我从cppreference.com知道std::declval<Foo>"添加"一个右值引用Foo,由于引用,折叠规则最终成为右值引用或左值引用.我的问题是为什么Foo没有调用构造函数?如何在std::declval<T>不构建模板参数的情况下实现"玩具"版本?
PS:我知道它与旧技巧不一样
(*(T*)(nullptr))
Run Code Online (Sandbox Code Playgroud) 有一些Stack Overflow用户强烈主张在编写函数时总是使用新的C++ 11尾随返回类型约定,例如main()->int.我可以看到优点,因为它使符号统一.但是,当声明一个函数指针时,我找不到任何使用尾随返回形式的方法,即可以声明
typedef int(*fp)(int);
要么
using fp = int(*)(int);
一个函数指针取一个int并返回一个int.
有没有办法在声明这样的函数指针时使用新的尾部返回语法?例如,像
using fp = (*)(int)->int;
但这不编译.如果没有,新语法不适用于函数指针是否有原因?
我有一个unordered_map使用字符串类型作为键:
std::unordered_map<string, value> map;
Run Code Online (Sandbox Code Playgroud)
提供std::hash专业化,也提供string合适的专业化operator==.
现在我还有一个"字符串视图"类,它是一个指向现有字符串的弱指针,避免了堆分配:
class string_view {
string *data;
size_t begin, len;
// ...
};
Run Code Online (Sandbox Code Playgroud)
现在,我希望能够使用string_view对象检查地图中是否存在密钥.不幸的是, std::unordered_map::find需要一个Key参数,而不是一般T参数.
(当然,我可以"推广"一个到一个string,但这会导致我想避免的分配.)
我喜欢的是类似的东西
template<class Key, class Value>
class unordered_map
{
template<class T> iterator find(const T &t);
};
Run Code Online (Sandbox Code Playgroud)
这将需要operator==(T, Key)并std::hash<T>()适当地定义,并将迭代器返回到匹配值.
有没有解决方法?
我想(想)我明白了auto.同样的decltype.但是,在C++ 14中,可以有一些像decltype(auto)生成函数的返回类型那样的代数.考虑以下:
decltype(auto) foo()
{
int m = 1;
return m;
}
Run Code Online (Sandbox Code Playgroud)
返回类型是int,一切都有意义.
然而,
decltype(auto) foo()
{
int m = 1;
return (m);
}
Run Code Online (Sandbox Code Playgroud)
返回int&(即引用int).
我绝对没有想到为什么会发生这种情况,为什么这些括号根本没有任何区别!?希望有人可以对此有所了解.
PS:我也标记过,C++因为有更多的人检查C++标签C++14.
我想std::random_device
用std::random_device::entropy()函数检查我的实现是否具有非零熵(即非确定性).但是,根据cppreference.com
"这个函数在某些标准库中没有完全实现.例如,即使设备是非确定性的,gcc和clang也总是返回零.相比之下,Visual C++总是返回32,而boost.random返回10."
有没有办法找到真正的熵?特别是,现代计算机(MacBook Pro/iMac等)是否具有非确定性源或随机性,例如使用散热监视器?
最常见的用法std::forward是,完美地转发转发(通用)引用,例如
template<typename T>
void f(T&& param)
{
g(std::forward<T>(param)); // perfect forward to g
}
Run Code Online (Sandbox Code Playgroud)
这param是一个lvalue,并std::forward最终将它转换为右值或左值,具体取决于与它有关的参数.
看一下cppreference.com的定义,std::forward我发现还有一个rvalue重载
template< class T >
T&& forward( typename std::remove_reference<T>::type&& t );
Run Code Online (Sandbox Code Playgroud)
任何人都可以给我任何rvalue超载的理由吗?我看不到任何用例.如果你想将一个右值传递给一个函数,你可以按原样传递它,不需要std::forward在它上面应用.
这与std::move我不同,我明白为什么人们也想要一个rvalue重载:你可能会处理通用代码,在这些代码中你不知道你传递了什么,你想要无条件支持移动语义,请参阅例如为什么std ::移动采取普遍参考?.
显式复制构造函数不允许使用类似的东西Foo foo = bar;,并强制执行复制用法Foo foo(bar);.此外,显式复制构造函数还禁止通过函数的值返回对象.但是,我尝试用大括号替换副本初始化,就像这样
struct Foo
{
Foo() = default;
explicit Foo(const Foo&) = default;
};
int main()
{
Foo bar;
Foo foo{bar}; // error here
}
Run Code Online (Sandbox Code Playgroud)
我收到了错误(g ++ 5.2)
错误:没有匹配函数来调用'Foo :: Foo(Foo&)'
或(clang ++)
错误:struct initializer中的多余元素
删除explicit使得代码在g ++下可编译,clang ++仍然失败并出现相同的错误(感谢@Steephen).这里发生了什么?统一初始化是否被视为初始化列表构造函数(胜过所有其他构建函数)?但如果是这种情况,为什么程序在复制构造函数非显式时编译?
c++ copy-constructor language-lawyer uniform-initialization c++11