- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我有带有转换运算符的简单代码,似乎所有编译器都给出了不同的结果,很好奇哪个编译器(如果有)是正确的?
我也尝试了不同的组合,但下面的组合是最有趣的。代码是使用 C++11 标志编译的,但在 C++03 中也可能观察到相同的行为。
#include <iostream>
struct call_operator {
template<typename T>
operator T() {
std::cout << __FUNCTION__ << std::endl;
return {};
}
template<typename T>
operator const T&() const {
std::cout << __FUNCTION__ << std::endl;
static T t;
return t;
}
template<typename T>
operator T&() const {
std::cout << __FUNCTION__ << std::endl;
static T t;
return t;
}
};
int main() {
(void)static_cast<int>(call_operator());
(void)static_cast<const int&>(call_operator());
(void)static_cast<int&>(call_operator());
}
operator int
operator const int &
operator int &
operator T
operator const T&
operator T&
call_operator.cpp(17): error C2440: 'static_cast': cannot convert from 'call_operator' to ' const int &'
template<typename T>
operator T();
call_operator::operator const int &
call_operator::operator const int &
call_operator::operator int &
template<typename T>
operator const T&();
call_operator.cpp:26:9: error: ambiguous conversion for static_cast from 'call_operator' to 'int' (void)static_cast<int>(call_operator());
operator T
operator const T&
operator T&
call_operator.cpp(16): error C2440: 'static_cast': cannot convert from 'call_operator' to 'int'
最佳答案
总之 :Clang 是正确的(尽管在一种情况下,出于错误的原因)。 GCC 在第二种情况下是错误的。 MSVC 在第一种情况下是错误的。
让我们从static_cast
开始(§5.2.9 [expr.static.cast]/p4,所有引用均来自 N3936):
An expression
e
can be explicitly converted to a typeT
using astatic_cast
of the formstatic_cast<T>(e)
if the declarationT t(e);
is well-formed, for some invented temporary variablet
(8.5). The effect of such an explicit conversion is the same as performing the declaration and initialization and then using the temporary variable as the result of the conversion. The expressione
is used as a glvalue if and only if the initialization uses it as a glvalue.
static_cast
这里实际上是三个初始化:
int t1(call_operator{});
const int & t2(call_operator{});
int & t3(call_operator{});
call_operator()
如
call_operator{}
仅用于说明目的,如
int t1(call_operator());
是最烦人的解析。这两种初始化形式之间存在小的语义差异,但这种差异对本次讨论无关紧要。
int t1(call_operator{});
if the source type is a (possibly cv-qualified) class type, conversion functions are considered. The applicable conversion functions are enumerated (13.3.1.5), and the best one is chosen through overload resolution (13.3). The user-defined conversion so selected is called to convert the initializer expression into the object being initialized. If the conversion cannot be done or is ambiguous, the initialization is ill-formed.
Assuming that “
cv1 T
” is the type of the object being initialized, and “cv S
” is the type of the initializer expression, withS
a class type, the candidate functions are selected as follows:
- The conversion functions of
S
and its base classes are considered. Those non-explicit conversion functions that are not hidden withinS
and yield typeT
or a type that can be converted to typeT
via a standard conversion sequence (13.3.3.1.1) are candidate functions. For direct-initialization, those explicit conversion functions that are not hidden withinS
and yield typeT
or a type that can be converted to typeT
with a qualification conversion (4.4) are also candidate functions. Conversion functions that return a cv-qualified type are considered to yield the cv-unqualified version of that type for this process of selecting candidate functions. Conversion functions that return “reference to cv2X
” return lvalues or xvalues, depending on the type of reference, of type “cv2X
” and are therefore considered to yieldX
for this process of selecting candidate functions.2 The argument list has one argument, which is the initializer expression. [ Note: This argument will be compared against the implicit object parameter of the conversion functions. —end note ]
operator T() - with T = int
operator const T& () const - with T = int
operator T&() const - with T = int
call_operator{}
组成,这是非常量。因此,它更好地转换为
operator T()
的非常量隐式对象参数。比其他两个。因此,
operator T()
是最佳匹配,由重载决议选择。
const int & t2(call_operator{});
A reference to type “cv1
T1
” is initialized by an expression of type “cv2T2
” as follows:
If the reference is an lvalue reference and the initializer expression
- is an lvalue (but is not a bit-field), and “cv1 T1” is reference-compatible with “cv2
T2
,” or- has a class type (i.e.,
T2
is a class type), whereT1
is not reference-related toT2
, and can be converted to an lvalue of type “cv3T3
,” where “cv1T1
” is reference-compatible with “cv3T3
” (this conversion is selected by enumerating the applicable conversion functions (13.3.1.6) and choosing the best one through overload resolution (13.3)).then the reference is bound to the initializer expression lvalue in the first case and to the lvalue result of the conversion in the second case (or, in either case, to the appropriate base class subobject of the object).
operator const T& () const - with T = int
operator T&() const - with T = int
const
.此外,由于两者都是直接引用绑定(bind),根据 §13.3.3.1.4 [ics.ref]/p1,从任一函数的返回类型到
const int &
所需的转换是身份转换。 (
不是 资格调整 - 指的是 §4.4 [conv.qual] 中描述的转换,仅适用于指针。)
operator T&()
执行的推导在这种情况下是不正确的‡。 §14.8.2.3 [temp.deduct.conv]/p5-6:
5 In general, the deduction process attempts to find template argument values that will make the deduced
A
identical toA
. However, there are two cases that allow a difference:
- If the original
A
is a reference type,A
can be more cv-qualified than the deduced A (i.e., the type referred to by the reference)- The deduced
A
can be another pointer or pointer to member type that can be converted toA
via a qualification conversion.6 These alternatives are considered only if type deduction would otherwise fail. If they yield more than one possible deduced
A
, the type deduction fails.
T
成功如
const int
为
operator T&()
对于推导类型和目标类型之间的精确匹配,不应考虑替代方案,
T
应该被推断为
const int
,而候选集实际上是
operator const T& () const - with T = int
operator T&() const - with T = const int
T
在
operator T&()
成为
const int
在这种情况下*。
operator const T& ()
比
operator T&()
更专业(由于 §14.8.2.4 [temp.deduct.partial]/p9 中的特殊规则),前者在 §13.3.3 [over.match.best]/p1 中以决胜局获胜,第二个列表,最后一个要点:
F1
andF2
are function template specializations, and the function template forF1
is more specialized than the template forF2
according to the partial ordering rules described in 14.5.6.2.
int & t3(call_operator{});
operator const T&();
根本不可能用于初始化
int &
.只有一个可行的功能,
operator T&()
与
T = int
,所以它是最好的可行函数。
operator const T&();
怎么办不是
const
?
int t1(call_operator{});
.两个强有力的竞争者是:
operator T() - with T = int
operator const T& () - with T = int
the context is an initialization by user-defined conversion (see 8.5, 13.3.1.5, and 13.3.1.6) and the standard conversion sequence from the return type of
F1
to the destination type (i.e., the type of the entity being initialized) is a better conversion sequence than the standard conversion sequence from the return type ofF2
to the destination type.
Standard conversion sequence
S1
is a better conversion sequence than standard conversion sequenceS2
if
S1
is a proper subsequence ofS2
(comparing the conversion sequences in the canonical form defined by 13.3.3.1.1, excluding any Lvalue Transformation; the identity conversion sequence is considered to be a subsequence of any non-identity conversion sequence)
int
来自
const int &
是左值到右值的转换,也就是左值转换。排除左值转换后,从结果到目的类型的标准转换顺序是相同的; §13.3.3.2 [over.ics.rank] 中的任何其他规则也不适用。
operator T()
之一和
operator const T&()
比另一个更专业。答案是不。详细的偏序规则相当复杂,但在§14.5.6.2 [temp.func.order]/p2 中的示例中很容易找到类似的情况,它标记了对
g(x)
的调用。由于含糊不清:
template<class T> void g(T);
template<class T> void g(T&);
const T&
另一个拿了
T
按值(value)来看,两者都不比另一个更专业**。因此,在这种情况下,没有唯一的最佳可行函数,转换不明确,代码格式错误。 †
operator T&()
推导出的类型case 是通过使用
operator const T&()
运行代码来确定的。移除。
const T&
和
T
产生相同的签名。然而,第 14.8.2.4 节 [temp.deduct.partial]/p9 包含一个特殊的规则,当有问题的两种类型都是引用类型时,这使得
operator const T&()
比
operator T&()
更专业;当其中一种类型不是引用类型时,该规则不适用。
operator const T&()
这种情况下可行的转换,但确实考虑了
operator T&()
一个可行的转换。
关于c++ - Clang vs GCC vs MSVC 模板转换运算符——哪个编译器是对的?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25745759/
我知道的引用资料在这里: http://clang.llvm.org/docs/ClangCommandLineReference.html http://clang.llvm.org/docs/Di
这两个工具似乎有一些共同的目标,而 documentation of clang-tidy对其功能非常明确,clang-check's有点稀疏。 如果我只能运行这些工具中的一个,同时进行相同的检查,那
我不清楚 clang 使用的汇编器。 AFAIK native 又名 GNU 汇编器和链接器被使用(与 gcc 一起提供)。 clang -v main.c clang version 3.4.2 T
在哪里可以找到 Clang 标志的完整列表? 还有一些,例如 -include-pch,甚至没有在手册页中列出。 :( 我知道 GCC 使用一些相同的标志,但它不包含诸如 -Os 之类的文档,我相信这
大多数成熟的编译器似乎对堆栈变量破坏有很好的支持。 海湾合作委员会:-fstack-protector xlC: -qstackprotect 英特尔:-fstackprotector window
我的命令: /usr/bin/c++ -fPIC -I/Users/me/project/include -I/usr/local/include/opencv \ -I/usr/local/incl
我正在研究 CLang 3.5。我正在尝试获取有关在 C++ 项目中声明的变量的信息。 如何获取 clang::VarDecl 中变量的数据类型或限定类名, clang::FieldDecl或 cla
我正在尝试构建 LLVM 编译器,以便我可以在 Apple M1 上启用 OpenMP。 我正在使用 LLVM 开发树,(因为我最近看到一些 OpenMP 运行时对此进行了处理)。 我已经结束了这个脚
背景: 在 Windows 10 PC 上,我有一个 C++ 代码库。使用 CMAKE 我生成了一个 Mingw-w64 项目(使用 Eclipse IDE)和一个 Visual Studio 201
下面是我想做的。 我想通过使用 cmake 的正确程序检测 clang 来使用 clang/clang++ 进行编译。 请告诉我可以解决我将描述的问题的正确程序。 test environment:
基本问题 我有以下代码 #include #include using namespace std; int main () { int32_t spam; spam=5; cout
当我在xcode中编译.c文件时,出现错误提示: clang error: argument unused during compilation: '-fno-objc-exceptions' [-W
Clang has several kinds of diagnostics ,其中三种主要是错误、警告和注释。 注释通常伴随着某些警告和错误,例如重复定义: error: conflicting t
我正在调整 Clang 工具模板(如 here 所述)以在我的代码中搜索特定的方法调用。为了稍后重写该调用,我想获取调用该方法的参数的类型,以及调用该方法的对象的类型。 我设法找到了一个可以回调以下内
我必须通过在它之前添加一个语句来检测 clang 中的某些语句。我有一个指向 Expr 对象的指针,我需要在包含它的语句之前插入另一个语句。现在我正在使用一种hacky方法,它只是将 SourceLo
类 clang::ASTContext 有一个方法: DynTypedNodeList getParents(const NodeT &Node) 它返回给定 AST 节点的父节点列表。 通常 AST
我想修改代码分析器程序clang-tidy的检查正在做,但是好像是配置文件.clang-tidy的内容正在被忽视。 我通过调用 clang-tidy 创建文件带旗-dump-config并将输出重定向
有没有办法用clang创建一个可以合理地适合页面的调用图? 即给出: #include using namespace std; int main() { int a; cin>>a;
我正在编写一个 Clang 工具,并且试图弄清楚如何在访问程序 AST 的情况下评估字符串文字。给定以下程序: class DHolder { public: DHolder(std::strin
我想在 Clang 中尝试一些新功能,有人提到我 Clang TOT . 现在这可能是一个明显的问题,到底是什么Clang TOT . TOT 一定是一些我不熟悉的首字母缩写词。 任何人都可以启发我吗
我是一名优秀的程序员,十分优秀!