- mongodb - 在 MongoDB mapreduce 中,如何展平值对象?
- javascript - 对象传播与 Object.assign
- html - 输入类型 ="submit"Vs 按钮标签它们可以互换吗?
- sql - 使用 MongoDB 而不是 MS SQL Server 的优缺点
假设我们有以下代码:
template <typename T>
void foo(const T&);
int main()
{
foo("str");
}
gcc 4.7.2、clang 3.2、icc 13.0.1
undefined reference to `void foo<char [4]>(char const (&) [4])'
MSVC-11.0
unresolved external symbol "void __cdecl foo<char const [4]>(char const (&)[4])" (??$foo@$$BY03$$CBD@@YAXAAY03$$CBD@Z)
注意第一个输出中的 char[4]
和第二个输出中的 char const[4]
。
为什么?谁是对的?请您引用标准吗?
最佳答案
GCC 是对的。
我们从一个稍微简单一点的例子开始,后面证明原来的例子也遵循同样的模式:
template<typename T>
void bar(T const&)
{
// Shall not fire
static_assert(std::is_same<T, int>::value, "Error!");
}
int main()
{
int x = 0;
bar(x); // 1 - Assertion won't fire
int const y = 0;
bar(y); // 2 - Assertion won't fire
}
这里发生了什么?首先,根据 § 14.8.2.1/3:
[...] If P is a reference type, the type referred to by P is used for type deduction. [...]
这意味着类型推导将尝试匹配 T const
反对int
(在情况 1)和反对 int const
(在案例 2 中)。在第二种情况下,替换 int
对于 T
将产生完美的匹配,所以这很容易;在第一种情况下,我们有 const
开始我们的完美匹配。但这就是第 14.8.2.1/4 条发挥作用的地方:
[...] If the original P is a reference type, the deduced A (i.e., the type referred to by the reference) can be more cv-qualified than the transformed A. [...]
这里,替换 int
对于 T
给我们一个推断的int const
, 比 int
更符合 cv 要求(参数的类型 x
)。但这是可以接受的,因为上面的 § 14.8.2.1/4,所以即使在这种情况下 T
推导出为 int
.
现在让我们处理您的原始示例(稍作调整,但我们最终会使用原始版本):
template<typename T>
void bar(T const&)
{
// Does not fire in GCC, fires in VC11. Who's right?
static_assert(std::is_same<T, char[4]>::value, "Error!");
}
int main()
{
char x[] = "foo";
bar(x);
char const y[] = "foo";
bar(y);
}
除了我替换了int
与 char []
,这是示例,我的第一个示例在结构上相同。要了解为什么这种等价性成立,请考虑下面的断言(正如预期的那样,它不会在 any 编译器上触发):
// Does not fire
static_assert(
std::is_same<
std::add_const<char [4]>::type,
char const[4]
>::value, "Error");
C++11 标准在第 3.9.3/2 段中规定了这种行为:
Any cv-qualifiers applied to an array type affect the array element type, not the array type (8.3.4).
第 8.3.4/1 段还规定:
[...] Any type of the form “cv-qualifier-seq array of N T” is adjusted to “array of N cv-qualifier-seq T”, and similarly for “array of unknown bound of T”. The optional attribute-specifier-seq appertains to the array. [ Example:
typedef int A[5], AA[2][3];
typedef const A CA; // type is “array of 5 const int”
typedef const AA CAA; // type is “array of 2 array of 3 const int”
—end example ] [ Note: An “array of N cv-qualifier-seq T” has cv-qualified type; see 3.9.3. —end note ]
由于现在很清楚这两个示例展示了相同的模式,因此应用相同的逻辑是有意义的。这将引导我们走上同样的推理路径。
在进行类型推断时,T const
与 char[4]
匹配在第一种情况下和反对char const[4]
第二种情况。
在第二种情况下,T = char[4]
产生完美匹配,因为 T const
变成 char const[4]
替换后。在第一种情况下,推导出的 A
再次比原来的 A
更符合 cv 要求, 在那个替换 char[4]
对于 T
产量 char const[4]
.但话又说回来,这是 14.8.2.1/4 允许的,所以 T
应推导出为 char[4]
.
最后,回到你原来的例子。由于字符串文字 "str"
也有类型 char const[4]
, T
应推导出为 char [4]
,表示GCC是对的:
template<typename T>
void foo(T const&)
{
// Shall not fire
static_assert(std::is_same<T, char[4]>::value, "Error!");
}
int main()
{
foo("str"); // Shall not trigger the assertion
}
关于c++ - 模板中的字符串文字 - 编译器的不同行为,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15501470/
如何使用 SPListCollection.Add(String, String, String, String, Int32, String, SPListTemplate.QuickLaunchO
我刚刚开始使用 C++ 并且对 C# 有一些经验,所以我有一些一般的编程经验。然而,似乎我马上就被击落了。我试过在谷歌上寻找,以免浪费任何人的时间,但没有结果。 int main(int argc,
这个问题已经有答案了: In Java 8 how do I transform a Map to another Map using a lambda? (8 个回答) Convert a Map>
我正在使用 node + typescript 和集成的 swagger 进行 API 调用。我 Swagger 提出以下要求 http://localhost:3033/employees/sear
我是 C++ 容器模板的新手。我收集了一些记录。每条记录都有一个唯一的名称,以及一个字段/值对列表。将按名称访问记录。字段/值对的顺序很重要。因此我设计如下: typedef string
我需要这两种方法,但j2me没有,我找到了一个replaceall();但这是 replaceall(string,string,string); 第二个方法是SringBuffer但在j2me中它没
If string is an alias of String in the .net framework为什么会发生这种情况,我应该如何解释它: type JustAString = string
我有两个列表(或字符串):一个大,另一个小。 我想检查较大的(A)是否包含小的(B)。 我的期望如下: 案例 1. B 是 A 的子集 A = [1,2,3] B = [1,2] contains(A
我有一个似乎无法解决的小问题。 这里...我有一个像这样创建的输入... var input = $(''); 如果我这样做......一切都很好 $(this).append(input); 如果我
我有以下代码片段 string[] lines = objects.Split(new string[] { "\r\n", "\n" }, StringSplitOptions.No
这可能真的很简单,但我已经坚持了一段时间了。 我正在尝试输出一个字符串,然后输出一个带有两位小数的 double ,后跟另一个字符串,这是我的代码。 System.out.printf("成本:%.2
以下是 Cloud Firestore 列表查询中的示例之一 citiesRef.where("state", ">=", "CA").where("state", "= 字符串,我们在Stack O
我正在尝试检查一个字符串是否包含在另一个字符串中。后面的代码非常简单。我怎样才能在 jquery 中做到这一点? function deleteRow(locName, locID) { if
这个问题在这里已经有了答案: How to implement big int in C++ (14 个答案) 关闭 9 年前。 我有 2 个字符串,都只包含数字。这些数字大于 uint64_t 的
我有一个带有自定义转换器的 Dozer 映射: com.xyz.Customer com.xyz.CustomerDAO customerName
这个问题在这里已经有了答案: How do I compare strings in Java? (23 个回答) 关闭 6 年前。 我想了解字符串池的工作原理以及一个字符串等于另一个字符串的规则是
我已阅读 this问题和其他一些问题。但它们与我的问题有些无关 对于 UILabel 如果你不指定 ? 或 ! 你会得到这样的错误: @IBOutlet property has non-option
这两种方法中哪一种在理论上更快,为什么? (指向字符串的指针必须是常量。) destination[count] 和 *destination++ 之间的确切区别是什么? destination[co
This question already has answers here: Closed 11 years ago. Possible Duplicates: Is String.Format a
我有一个Stream一个文件的,现在我想将相同的单词组合成 Map这很重要,这个词在 Stream 中出现的频率. 我知道我必须使用 collect(Collectors.groupingBy(..)
我是一名优秀的程序员,十分优秀!