namespace X {
void f();
}
void X::f() {
void g();
g();
}
Run Code Online (Sandbox Code Playgroud)
我宣布了::g,还是X::g?
如果我添加一个定义X::g:clang 3.5将编译并链接这个:
namespace X {
void f();
}
void X::f() {
void g();
g();
}
void X::g() { }
Run Code Online (Sandbox Code Playgroud)
gcc 4.9.1用消息拒绝定义:
错误:'void X :: g()'应该在'X'内声明
但是,如果我g在全局命名空间中定义,gcc似乎改变了它的想法并且抱怨相反:
Run Code Online (Sandbox Code Playgroud)Undefined symbols for architecture x86_64: "X::g()", referenced from: X::f() in ccABCDEF.o
因为void ::g()在内部声明也是非法的f,似乎不可能在命名空间函数中具有全局函数的函数范围前向声明.我错过了什么吗?这里的范围规则究竟是什么?
g ++(GCC)4.9.1; Apple LLVM 6.0版(clang-600.0.54)(基于LLVM 3.5svn)
C++ 17标准似乎说如果指针指向数组元素,则只能将一个整数添加到指针中,或者,作为特殊异常,指针是一元运算符的结果&:
8.5.6 [expr.add]描述对指针的添加:
当向指针添加或从指针中减去具有整数类型的表达式时,结果具有指针操作数的类型.如果表达式P指向具有n个元素的数组对象 x的元素x [i] ,则表达式P + J和J + P(其中J具有值j)指向(可能是假设的)元素x [i + j]如果0≤i+j≤n; 否则,行为未定义.
该引言包括一个非规范的脚注:
为此目的,不是数组元素的对象被认为属于单元素数组; 见8.5.2.1
引用8.5.2.1 [expr.unary.op]讨论一元运算&符:
一元&运算符的结果是指向其操作数的指针...出于指针运算(8.5.6)和比较(8.5.9,8.5.10)的目的,一个不是数据元素的对象,其地址被采用以这种方式被认为属于具有T类型的一个元素的数组.
非规范性脚注似乎有些误导,因为它引用的部分描述了一元运算符结果的特定行为&.似乎没有任何东西允许其他指针(例如来自非数组new)被认为是单元素数组.
这似乎表明:
void f(int a) {
int* z = (new int) + 1; // undefined behavior
int* w = &a + 1; // ok
}
Run Code Online (Sandbox Code Playgroud)
这是对C++ 17所做更改的疏忽吗?我错过了什么吗?是否有理由认为"单元素数组规则"仅针对一元运算符提供&?
注意:如标题中所述,此问题特定于C++ 17.C标准和C++标准的早期版本包含不再存在的明确的规范性语言.像这样的老问题模糊不清楚.
最新版本的clang(3.9)在第二行拒绝了这段代码f; 最新版本的gcc(6.2)接受它:
struct Y {
Y();
Y(const Y&);
Y(Y&&);
};
struct X {
operator const Y();
};
void f() {
X x;
Y y(x);
}
Run Code Online (Sandbox Code Playgroud)
如果进行了任何这些更改,clang将接受以下代码:
Y移动构造函数const从转换运算符中删除Y y(x)为Y y = x原始示例合法吗?哪个编译器错了?在检查标准中有关转换函数和重载分辨率的部分之后,我还未能找到明确的答案.
c++ initialization type-conversion conversion-operator language-lawyer
int test[2] = { 45, test[0] };
int x = (x = 111);
cout << test[0] << " " << test[1] << " " << x << "\n"; // 45 45 111
Run Code Online (Sandbox Code Playgroud)
前两行的作业是否合法?Visual Studio 2010编译并运行它没有任何错误或警告但似乎奇怪的情况可能是未定义的,所以我想确认它是可以接受的.Visual Studio会警告我,如果我做了一些公然反身(并且可能是未定义的),int x = x;那么我想知道这些情况似乎是如何处理的.
在给定重载集和参数列表的情况下,是否可以确定重载决策将选择的候选函数类型?例如,给定:
char* f(int);
int f(char*);
Run Code Online (Sandbox Code Playgroud)
我希望能够写出如下内容:
overload<f, short>::type x;
Run Code Online (Sandbox Code Playgroud)
声明一个x类型的变量char* (*)(int).
这可能吗?我的第一直觉是写下这样的东西:
template<typename... Args>
struct overload {
template<typename Ret>
static auto deduce(Ret (*fptr)(Args...)) -> decltype(fptr);
};
Run Code Online (Sandbox Code Playgroud)
...但是这不能处理非完全匹配(即decltype(overload<int>::deduce(f))工作,但decltype(overload<short>::deduce(f))不能).
c++ templates overload-resolution template-meta-programming c++11
考虑这个包含成员函数和成员函数模板的类模板的示例,这两个模板都被命名,f然后尝试定义和专门化成员函数模板:
template<typename T>
struct A {
void f();
template<typename U>
void f();
};
template<>
template<typename U>
void A<double>::f() { }
template<>
template<>
void A<double>::f<int>() { }
Run Code Online (Sandbox Code Playgroud)
这合法吗?成员函数模板定义应该怎么写?
在 的第一个定义中f,模板声明是否确保即使模板参数没有出现在类型中,也f应选择成员函数模板而不是成员函数?f我没有看到任何方法可以进一步消除歧义,因为编写::template f()、::f<U>()、::f<>()或它们的组合似乎没有帮助。
编译结果:
f<int>fgcc:在第一个定义处出现编译错误(正在定义的内容不明确)f相比之下,每个编译器都接受命名空间范围内的等效内容:
namespace X {
void f();
template<typename T>
void f();
}
template<typename T>
void X::f() { }
template<>
void X::f<int>() { }
Run Code Online (Sandbox Code Playgroud) 在任何"主要平台"(我为了这个问题而定义为Windows,Mac和Linux),可以想象一个有效分配的指针在程序地址空间中的地址0处分配(因此搞乱)与NULL进行比较?)标准是否甚至允许编译器/平台在地址0处进行有效分配?
下面的代码(编译和执行得当,做我想要的)是一个怪胎,而写一个类来存储需要删除的指针,当它不再知道自己的类型的能力不同类型的属性,我经历的一个小例子.我的解决方案是使用模板化函数创建一个Deleter类,该函数可以获取并存储其地址以删除特定类型.我不明白为什么这段代码有效,具体来说:
码:
#include <iostream>
#include <string>
#include <cassert>
#include <locale> //Just here as an unused class to specialize
using namespace std;
typedef void(*void_voidptr_func_t)(void*);
class ClassWithDestructor {
public:
~ClassWithDestructor() {
cout << "Destroyed\n";
}
};
class Deleter {
public:
template <class T>
static void Delete (T* ptr) {
assert(0);
}
//locale here can be any class
//it doesn't matter what class it is
//but if this specialization doesn't exist
//compile fails
template <class locale>
static void Delete(void* …Run Code Online (Sandbox Code Playgroud) 我查看了lexical_cast.hpp的混乱,这继续逃避我.
lexical_cast,其"基本定义"同时采用模板源和目标,能够接受诸如lexical_cast<int>("7")?之类的语法?我不知道它怎么只需要一个模板化的返回类型,并且不需要你给出参数的类型而不做像部分模板特化这样的非法操作.
注意:我理解如何使用单个模板类型和不同参数的重载来完成此操作,但我无法理解lexical_cast是如何基于需要源模板类型和目标模板类型的模板函数.