在C++ Primer一书中,有一个关于函数模板重载的例子:
Run Code Online (Sandbox Code Playgroud)// print any type we don't otherwise handle template <typename T> string debug_rep(const T &t) { cout << "debug_rep(T const&)\n"; ostringstream ret; // see § 8.3 (p. 321) ret << t; // uses T's output operator to print a representation of t return ret.str(); // return a copy of the string to which ret is bound } // print pointers as their pointer value, followed by the object to which the pointer points // NB: this …
c++ template-argument-deduction function-templates-overloading
您好,我有一个简单的问题:是否在同一个表达式中多次修改对象;一次通过其标识符(名称),第二次通过对它的引用或指向它的指针 未定义行为?
int i = 1;
std::cout << i << ", " << ++i << std::endl; //1- Error. Undefined Behavior
int& refI = i;
std::cout << i << ", " << ++refI << std::endl; //2- Is this OK?
int* ptrI = &refI; // ptrI point to the referred-to object (&i)
std::cout << i << ", " << ++*ptrI << std::endl; // 3 is this also OK?
Run Code Online (Sandbox Code Playgroud)
在第二个中,它似乎工作正常,但我对此感到困惑,因为从我所学到的;引用只是一个已经存在的对象的别名。并且对它的任何更改都会影响被引用的对象。因此,我在这里看到的是i
和refI
是相同的,因此在同i
一个表达式中不止一次修改同一个对象 ( )。
但是为什么所有编译器都将语句 2 视为定义良好的行为?
语句 3 …
我一直在努力理解std::strlen()
但徒劳无功:
AFAIKstrlen()
以字节为单位返回以空字符结尾的常量字符串中的字符数。如果它不是以 null 结尾的,则行为是未定义的。除此之外,还可以。
所以:std::strlen("");
是 0。
但是,因为我已经在 www.cppreference.com 上阅读过它,所以我发现了一个可能的实现:
// This is from: https://en.cppreference.com/w/cpp/string/byte/strlen
std::size_t strlen(const char* start) {
const char* end = start;
while(*++end != 0);// I think this causes UB
return end - start;
}
Run Code Online (Sandbox Code Playgroud)
但是如果我运行它:
int main()
{
const char cp1[] = "";
const char cp2[] = "\0";
const char cp3[] = "\0Hello";
const char cp4[] = "H\0ello";
const char cp5[1] = {};// UB?
const char cp6[] = {'\0'};
const char …
Run Code Online (Sandbox Code Playgroud) 在C++ Primer 第 5 版中。, 第 14 章讨论转换运算符:
在该标准的早期版本中,想要定义到 bool 的转换的类面临一个问题:因为 bool 是一种算术类型,转换为 bool 的类类型对象可以在任何需要算术类型的上下文中使用。
这种转换可能以令人惊讶的方式发生。特别是,如果 istream 转换为 bool,则以下代码将编译:
Run Code Online (Sandbox Code Playgroud)int i = 42; cin << i; // this code would be legal if the conversion to bool were not explicit!
该程序尝试在输入流上使用输出运算符。没有
<<
定义 foristream
,所以代码几乎肯定是错误的。然而,这个代码可以使用布尔转换操作符转换cin
到bool
。然后将生成的 bool 值提升为 int 并用作左移运算符的内置版本的左侧操作数。提升的布尔值(1 或 0)将左移 42 个位置。
输入流可以转换为表示流内部状态(成功或失败)的布尔值。我们曾经这样做:
while(std::cin >> str)...
Run Code Online (Sandbox Code Playgroud)
那么为什么不应该编译呢?
int x = 0;
std::cin << x;
Run Code Online (Sandbox Code Playgroud)
如果我使用显式转换,它会起作用:
(bool)cin << 5; // works although bad
Run Code Online (Sandbox Code Playgroud) 当类中有一个未定义移动操作的成员时,我很难理解隐式移动操作:
int main() {
struct A // no move: move = copy
{
A() = default;
A(const A&) {
cout << "A'copy-ctor\n";
};
A& operator=(const A&) {
cout << "A'copy-assign\n";
return *this;
}
};
struct B
{
B() = default;
A a; // does this make B non-moveable?
unique_ptr<int> upi;
// B(B&&) noexcept = default;
// B& operator=(B&&)noexcept = default;
};
A a;
A a2 = std::move(a); // ok use copy ctor instead of move one
a2 = std::move(a); // …
Run Code Online (Sandbox Code Playgroud) c++ copy-constructor move-constructor implicit-methods c++11
好奇的是,为什么std::sqrt
andstd::pow
只针对单一类型的参数进行重载?为什么它们不作为函数/函子模板实现?
我试图模拟class vector
它,iterator
所以这是问题所在:
template<class T>
class vec {
public:
vec();
vec(const int);
virtual ~vec();
T* getElem()const;
const int size()const;
void resize(const int);
void print()const;
T& operator[](int);
struct iterator {
T* elem;
iterator* operator++();
};
iterator begin();
iterator end();
private:
T* elem;
int sz;
};
Run Code Online (Sandbox Code Playgroud)
现在我需要iterator begin();
在课外实现vec
:
template<class T>
vec<T>::iterator vec<T>::begin() {
vec<T>::iterator tmp;
tmp.elem = elem;
return tmp;
}
Run Code Online (Sandbox Code Playgroud)
我收到警告:
Severity Code Description Project File Line
Warning C4346 iterator': dependent name is not …
Run Code Online (Sandbox Code Playgroud) 据我所知,std::allocator
是由库引入的,用于分配未初始化的未构造内存块。所以:
std::allocator<int> a;
auto ptr = a.allocate(100);
auto e = ptr;
while (e != ptr + 5)
a.construct(e++, 0);
for (auto tmp = ptr; tmp != e; )
std::cout << *tmp++ << ", ";
std::cout << std::endl;
std::allocator<int> a2;
std::allocator<int> a3 = a;
for (auto tmp = ptr; tmp != e; )
a.destroy(tmp++);
//for (auto tmp = ptr; tmp != e; )
// a2.destroy(tmp++); // is it UB using a2 here to destroy elements?
//for (auto tmp = …
Run Code Online (Sandbox Code Playgroud) 我有这个来自 C++ 第五版的例子:
template <typename T> T fobj(T, T); // arguments are copied
template <typename T> T fref(const T&, const T&); // references
string s1("a value");
const string s2("another value");
fobj(s1, s2); // calls fobj(string, string); const is ignored
fref(s1, s2); // calls fref(const string&, const string&)
// uses premissible conversion to const on s1
int a[10], b[42];
fobj(a, b); // calls f(int*, int*)
fref(a, b); // error: array types don't match
Run Code Online (Sandbox Code Playgroud)
“在接下来的一对调用中,我们传递数组参数,其中数组的大小不同,因此具有不同的类型。在调用中fobj
,数组类型不同的事实并不重要。两个数组都被转换为指针。模板参数类型中fobj
是int*
。所述的呼叫fref …
正如我们所知,我们必须typename
在使用模板类型参数的类型成员之前进行perpend ,因为没有它,编译器不知道我们是访问类型成员还是使用静态数据成员,因为类模板的定义不是尚未存在(实例化)
template <typename T>
void foo()
{
T::type x{}; // error: need a typename
typename T::type y{}; // ok
}
Run Code Online (Sandbox Code Playgroud)
到这里为止还可以,但是我发现了这个问题:
template <typename C_>
C_::value_type get_sum(C_ const& c) // no need to typename?!
{
C_::value_type sum0{}; // errorL: need to typename keyword
typename C_::value_type sum{};
for(auto const& i : c)
sum += i;
return sum;
}
Run Code Online (Sandbox Code Playgroud)
正如您在函数模板主体中所看到的,编译器抱怨缺少关键字,typename
但将其用作返回类型却没有抱怨?有人可以解释为什么吗?