我有一个我在实现低级泛型类型时使用的组件,它存储任意类型的对象(可能是也可能不是类类型),它可能是空的,以利用空基本优化:
template <typename T, unsigned Tag = 0, typename = void>
class ebo_storage {
T item;
public:
constexpr ebo_storage() = default;
template <
typename U,
typename = std::enable_if_t<
!std::is_same<ebo_storage, std::decay_t<U>>::value
>
> constexpr ebo_storage(U&& u)
noexcept(std::is_nothrow_constructible<T,U>::value) :
item(std::forward<U>(u)) {}
T& get() & noexcept { return item; }
constexpr const T& get() const& noexcept { return item; }
T&& get() && noexcept { return std::move(item); }
};
template <typename T, unsigned Tag>
class ebo_storage<
T, Tag, std::enable_if_t<std::is_class<T>::value>
> : …Run Code Online (Sandbox Code Playgroud) 在C++标准§13.3.1.7[over.match.list]中,陈述如下:
在copy-list-initialization中,如果
explicit选择了构造函数,则初始化是错误的.
这就是为什么我们不能这样做的原因,例如:
struct foo {
// explicit because it can be called with one argument
explicit foo(std::string s, int x = 0);
private:
// ...
};
void f(foo x);
f({ "answer", 42 });
Run Code Online (Sandbox Code Playgroud)
(注意,这里发生的不是转换,即使构造函数是"隐式的"也不会是一个.这是一个foo对象直接使用它的构造函数初始化.除此之外std::string,这里没有转换.)
这对我来说似乎完全没问题.隐式转换不会让我感到困惑.
如果{ "answer", 42 }可以初始化其他东西,编译器不会背叛我并做错事:
struct bar {
// explicit because it can be called with one argument
explicit bar(std::string s, int x = 0);
private:
// ...
};
void f(foo x);
void f(bar x); …Run Code Online (Sandbox Code Playgroud) 如果你要查看这段代码,
int x = 0;
function(x);
std::cout << x << '\n';
Run Code Online (Sandbox Code Playgroud)
您将无法通过任何语法方式验证参数x是通过引用传递还是通过值传递.您可以肯定的唯一方法是查看函数声明或函数定义.
这是一个简单的例子,我认为这可能是一个问题:
std::string Lowercase(std::string str); //<- this is hidden away in code; probably in a different file.
int main(){
std::string str = "HELLO";
Lowercase(str);
std::cout << str << '\n'; //<- Bug! we expected to output "hello". The problem is not very easy to spot, especially when a function name sounds as though it will change the passed in value.
}
Run Code Online (Sandbox Code Playgroud)
为了避免必须在函数调用和函数声明(或在某些情况下,文档)之间跳转以理解函数行为,有没有办法在函数调用的语法中显式地记录参数是期望改变(即参考参数)或发送副本(即通过值传递)?
我意识到还有一个选择传递const&,它具有类似于传递值的概念,因为传入的变量在函数调用之后不会更改其值.
我确信语言中有各种各样的情况可能会增加理解参数传递的复杂性 - 但我很好奇,有没有办法以我想要的方式解决这个问题? …
不知道发生了什么.我查看了与此问题类似的其他帖子,但到目前为止还没有任何解决方案.这是包含错误的部分的注释的代码.有一次,它说!=不起作用,在其余的代码中,它说<<不起作用.
#include <iostream>
#include <algorithm>
#include <vector>
#include <ctime>
#include <cstdlib>
#include <cctype>
using namespace std;
//Hangman
int main()
{
//setup
vector<string> words;
words.push_back("GUITAR");
words.push_back("VIRGINIA");
words.push_back("LAPTOP");
words.push_back("WIFEY");
words.push_back("IPHONE");
srand(static_cast<unsigned int>(time(0))); //randomly select a word
random_shuffle(words.begin(), words.end());
const string THE_WORD = words[0];
const int MAX_WRONG = 8; //initialize wrong guesses
int wrong = 0;
string soFar(THE_WORD.size(), '-'); //initalize the word so far with dashes
string used = " "; //initalize letters used
cout << "Welcome to Hangman. Good luck!/n";
//game loop …Run Code Online (Sandbox Code Playgroud) 除非我在initializer_list之前放置constexpr,否则以下内容无法编译:
constexpr std::initializer_list<int> il = {
1, 2, 3, 4, 5, 6, 7, 8, 9, 10
};
std::array<int, il.size()> a;
Run Code Online (Sandbox Code Playgroud)
但是initializer_list的大小是constexpr:
constexpr size_type size() const;
Run Code Online (Sandbox Code Playgroud) 在2003年 - 是的,2003年 - 范德沃德和约瑟特在他们的书"C++模板"(第40页)中写道:
无法使用浮点文字(和简单的常量浮点表达式)作为模板参数具有历史原因.因为没有严重的技术挑战,所以在未来的C++版本中可能会支持这一点.
但即使在C++ 11下,这仍然无效:
template<double D> //error
void foo() {}
Run Code Online (Sandbox Code Playgroud)
为什么没有添加?
如果我将一个整数转换为枚举类会发生什么,但枚举中不存在该值?例如:我想要一个函数来测试整数是否具有来自枚举类的某个值:
enum class EnumClass { A, B = 4, C = 9, D = 60 };
bool checkEnumClass( int v )
{
switch( static_cast< EnumClass >( v ) )
{
case EnumClass::A:
case EnumClass::B:
case EnumClass::C:
case EnumClass::D:
return true;
default:
return false;
}
}
checkEnumClass( 0 ) == true;
checkEnumClass( 7 ) == false; // is this true?
Run Code Online (Sandbox Code Playgroud)
这是检查整数是否可以转换为枚举的正确方法吗?
考虑以下小代码片段:
#include <iostream>
template<class T>
int test();
int main()
{
std::cout << test<int>() << "\n";
}
// POI for test<int>() should be right here
template<class T>
int test()
{
return 0;
}
Run Code Online (Sandbox Code Playgroud)
实例,为Clang和g ++编译并打印0.
14.6.4.1实例化点[temp.point]
1对于函数模板特化,成员函数模板特化,或成员函数或类模板的静态数据成员的特化,如果特化是隐式实例化的,因为它是从另一个模板特化和其中的上下文中引用的引用取决于模板参数,专门化的实例化点是封闭专门化的实例化点.否则,这种特化的实例化点紧跟在引用特化的命名空间范围声明或定义之后.
Vandevoorde和Josuttis对此有以下说法:
实际上,大多数编译器会将非内联函数模板的实际实例化延迟到翻译单元的末尾.这有效地将相应模板特化的POI移动到翻译单元的末尾.C++语言设计者的目的是使其成为一种有效的实现技术,但该标准并未明确这一点.
问题:Clang/g ++是否不符合要求,因为它们将POI延迟到翻译单元的末尾?
我有一个类Foo,它是一个自引用树状结构(最低限度):
class Foo {
public:
// Gets this child's position relative to it's parent.
int getPosition() const {
return parent->indexOf(this);
}
int indexOf(const Foo *const child) const {
return children.indexOf(child); // this line causes an error.
}
private:
Foo *parent;
QList<Foo *> children;
}
Run Code Online (Sandbox Code Playgroud)
该行return children.indexOf(child)期望const T &value按照QList文档传递,这解决Foo *const &value了我的方案.
为了让我的getPosition()方法调用我自己的indexOf()方法,需要const Foo *child至少具有一个签名,以便this从const方法传递.(因为这是const Foo *const).
我的代码不会编译,因为const Foo *const child …
我在这段代码中有内存损坏:
#include <string>
#include <iostream>
#include <vector>
#include <initializer_list>
int main() {
std::vector<std::initializer_list<std::string>> lists = {
{
{"text1"},
{"text2"},
{"text3"}
},
{
{"text4"},
{"text5"}
}
};
int i = 0;
std::cout << "lists.size() = " << lists.size() << std::endl;
for ( auto& list: lists ) {
std::cout << "lists[" << i << "].size() = " << lists[i].size() << std::endl;
int j = 0;
for ( auto& string: list ) {
std::cout << "lists[" << i << "][" << j << …Run Code Online (Sandbox Code Playgroud)