当在函数之间传递r值时,我想知道c ++行为.
看看这个简单的代码:
#include <string>
void foo(std::string&& str) {
// Accept a rvalue of str
}
void bar(std::string&& str) {
// foo(str); // Does not compile. Compiler says cannot bind lvalue into rvalue.
foo(std::move(str)); // It feels like a re-casting into a r-value?
}
int main(int argc, char *argv[]) {
bar(std::string("c++_rvalue"));
return 0;
}
Run Code Online (Sandbox Code Playgroud)
我知道当我在bar
函数内部时我需要使用move
函数来调用foo
函数.我现在的问题是为什么?
当我在bar
函数内部时,变量str
应该已经是一个r值,但编译器就像是一个l值.
有人可以引用一些关于这种行为的标准吗?谢谢!
给出以下源代码:
#include <memory>
#include <typeinfo>
struct Base {
virtual ~Base();
};
struct Derived : Base { };
int main() {
std::unique_ptr<Base> ptr_foo = std::make_unique<Derived>();
typeid(*ptr_foo).name();
return 0;
}
Run Code Online (Sandbox Code Playgroud)
并编译它:
clang++ -std=c++14 -Wall -Wextra -Werror -Wpedantic -g -o test test.cpp
环境设置:
linux x86_64
clang version 5.0.0
Run Code Online (Sandbox Code Playgroud)
由于警告(注释-Werror
)它不编译:
error: expression with side effects will be evaluated
despite being used as an operand to 'typeid'
[-Werror,-Wpotentially-evaluated-expression]
typeid(*ptr_foo).name();
Run Code Online (Sandbox Code Playgroud)
(请注意:海湾合作委员会并未声称存在这种潜在问题)
题
有没有办法获得有关a指向的类型的信息unique_ptr
而不产生那种警告?
注意:我不是在谈论禁用-Wpotentially-evaluated-expression
或避免-Werror
.
以下代码应该编译吗?
#include <type_traits>
void foo() {
const std::pair<int, int> x = {1, 2};
auto [a, b] = x;
static_assert(std::is_const_v<decltype(a)>);
static_assert(std::is_const_v<decltype(b)>);
}
Run Code Online (Sandbox Code Playgroud)
那么,这是MSVC错误吗?
该标准是不是直接在这里(我有一个快速浏览一下),但考虑规则auto
,我想,a
并且b
应该被复制丢弃CV-预选赛。
我有这个简单的代码:
#include <iostream>
#include <fstream>
#include <system_error>
int main(int argc, char *argv[]) {
std::ifstream file;
file.exceptions(std::ios::failbit | std::ios::badbit);
try {
file.open("a_file_does_not_exist.txt", std::ios::in);
file.close();
} catch(const std::ios_base::failure& err) {
std::cerr << err.code() << std::endl;
return -1;
}
return 0;
}
Run Code Online (Sandbox Code Playgroud)
刚刚完成,这是编译命令:
g++ -std=c++11 -g // ...
Run Code Online (Sandbox Code Playgroud)
编译器的版本是g ++(GCC)6.1.1.
平台:arch-linux 4.7.2-1.
可以想象,该文件不存在,因此该方法file.open(...)
将引发异常.问题是,当我运行代码的异常没有被处理,而std::terminate
被调用.
奇怪的是输出:
terminate called after throwing an instance of 'std::ios_base::failure'
what(): basic_ios::clear
Annullato (core dump creato)
Run Code Online (Sandbox Code Playgroud)
正如你所读到的那样,投掷课是一个std::ios_base::failure
,但我的抓住是正确的. …
我们已经知道,VLA(在C99中标准化)不是C++标准的一部分.
所以下面的代码在C++中是"非法的":
void foo(int n) {
int vla[n];
for (int i = 0; i < n; ++i) {
vla[i] = i;
}
}
Run Code Online (Sandbox Code Playgroud)
尽管编译器(g ++和clang ++)接受代码作为有效语法,但只有在启用情况下才会生成警告 .-pedantic
ISO C++禁止变长数组'vla'[-Wvla]
我的问题是:
为什么编译器接受该声明?
编译器不能只拒绝一个长度为的数组[is-no-know-at-compile-time]
?
是否存在一种兼容性语法规则?
标准说了什么?
从生成的汇编代码中我看到编译器在循环中写入堆栈,就像普通数组一样,但我找不到任何关于标准行为的信息.
我有一个简单的模板函数do_something,它返回一个整数:123.
template<typename T>
auto do_something(T input) {
std::this_thread::sleep_for(std::chrono::seconds(1));
return 123;
}
int main(int argc, char *argv[]) {
std::function<int(void)> function = std::bind(do_something<int>, 12);
function();
return 0;
}
Run Code Online (Sandbox Code Playgroud)
使用GCC 6.1.1,我收到此错误:
test.cpp: In function ‘int main(int, char**)’:
test.cpp:16:70: error: no matching function for call to ‘bind(<unresolved overloaded function type>, int)’
std::function<int(void)> function = std::bind(do_something<int>, 12);
^
In file included from /usr/include/c++/6.1.1/thread:39:0,
from test.cpp:4:
/usr/include/c++/6.1.1/functional:1331:5: note: candidate: template<class _Func, class ... _BoundArgs> typename std::_Bind_helper<std::__is_socketlike<_Func>::value, _Func, _BoundArgs ...>::type std::bind(_Func&&, _BoundArgs&& ...) …
Run Code Online (Sandbox Code Playgroud) 我正在读这个问题.
问题本身并不那么有趣,但我想知道它是否存在以及如何实现编译时解决方案.
关于第一个序列:
所有数字除了可以除以3之外的数字.
序列应该是这样的:
[1, 2, 4, 5, 7, 8, 10, 11, 13, 14, ...]
Run Code Online (Sandbox Code Playgroud)
通过归纳,我找到了该序列的数学公式:
f(0) = 0;
f(x > 0) = floor[(3x - 1) / 2];
Run Code Online (Sandbox Code Playgroud)
所以我实现了一个C++ constexpr
函数,它在序列中生成第i个数字:
#include <type_traits>
template <typename T = std::size_t>
constexpr T generate_ith_number(const std::size_t index) {
static_assert(std::is_integral<T>::value, "T must to be an integral type");
if (index == 0) return 0;
return (3 * index - 1) / 2;
}
Run Code Online (Sandbox Code Playgroud)
现在我想生成一个"编译时数组/序列",它存储序列的前N个数字.
结构应该是这样的:
template <typename …
Run Code Online (Sandbox Code Playgroud) 我们假设有一个template
班级Foo
:
template <typename T>
class Foo {
void foo();
};
Run Code Online (Sandbox Code Playgroud)
我有另一个template
类Bar
(独立于第一个类):
template <int N>
class Bar {};
Run Code Online (Sandbox Code Playgroud)
让我们说,我想专门foo()
为任何Bar
类的方法.我写错了:
template <>
template <int N>
void Foo<Bar<N> >::foo() { /* ... */ }
Run Code Online (Sandbox Code Playgroud)
编译器指责我,因为类型不完整:
error: invalid use of incomplete type 'class Foo<Bar<N> >'
void Foo<Bar<N> >::foo() { }
Run Code Online (Sandbox Code Playgroud)
我正在使用C++ 98,但我想知道C++ 11中是否存在不同的解决方案.
我可以解决专门Foo
针对泛型的整个类的问题Bar
,但是在我必须定义所有方法之后.
这不是我想要的,我正在寻找(如果存在)更优雅的解决方案(包括C++ 98和C++ 11),它允许我专门化并实现单个类方法.
关于SO的问题没有解释如何专注于模板参数.实际上,我的问题显示了编译器如何抱怨这一点.
我在探索丑陋的世界std::intializer_list
.
据我所知,从标准:
§11.6.4:
- std :: initializer_list类型的对象是从初始化列表构造的,就好像实现生成并实现了(7.4)类型为"const const E"的prvalue,其中N是初始化列表中的元素数.使用初始化列表的相应元素对该数组的每个元素进行复制初始化,并构造std :: initializer_list对象以引用该数组.[注意: 在初始化列表的上下文中,可以访问为副本选择的构造函数或转换函数(第14条). - 尾注] [...]
因此,如果类型E
是一个类,我希望调用复制构造函数.
以下类不允许复制构造:
struct NonCopyable {
NonCopyable() = default;
NonCopyable(const NonCopyable&) = delete;
};
Run Code Online (Sandbox Code Playgroud)
我将尝试std::initializer_list
使用此类实例化一个.
#include <vector>
void foo() {
std::vector<NonCopyable>{NonCopyable{}, NonCopyable{}};
}
Run Code Online (Sandbox Code Playgroud)
随着g++-8.2 -std=c++14
我得到我期望的,编译器错误:
error: use of deleted function 'NonCopyable::NonCopyable(const NonCopyable&)'
.
完善!
但是,行为随新标准而变化.
的确,g++-8.2 -std=c++17
编译.
我认为这是因为copy elision
新标准提出的新要求,起初.
但是,更改标准库实现 …
使用SFINAE,我需要检测容器的某些属性。
例如:
#include <type_traits>
#include <vector>
template <typename Container, typename = void>
struct Trait {};
template <typename Container>
struct Trait<
Container,
std::enable_if_t<std::is_integral_v<typename Container::value_type>>> {
static constexpr bool foo = false;
};
template <typename Container>
struct Trait<
Container,
std::enable_if_t<std::is_floating_point_v<typename Container::value_type>>> {
static constexpr bool foo = true;
};
static_assert(Trait<std::vector<int>>::foo == false);
static_assert(Trait<std::vector<double>>::foo == true);
Run Code Online (Sandbox Code Playgroud)
上面的代码可以按预期进行编译和运行(在clang和gcc上)。在这里检查。
但是,如果我稍加修改将模板类型包装在里面的代码std::void_t
:
template <typename Container>
struct Trait<
Container,
std::void_t<std::enable_if_t<std::is_integral_v<typename Container::value_type>>>> {
static constexpr bool foo …
Run Code Online (Sandbox Code Playgroud)