gpt4 book ai didi

c++ - clang 中明确指定的参数无效,但在 gcc 中编译成功——谁错了?

转载 作者:可可西里 更新时间:2023-11-01 17:56:42 25 4
gpt4 key购买 nike

以下代码在 g++ 中编译没有问题:

#include <iostream>
#include <string>
#include <tuple>

template<typename T>
void test(const T& value)
{
std::tuple<int, double> x;
std::cout << std::get<value>(x);
}

int main() {
test(std::integral_constant<std::size_t,1>());
}

我使用了这个命令:

g++ test.cpp -o test -std=c++14 -pedantic -Wall -Wextra

但是,当我将 g++ 切换到 clang++(使用 g++ 5.1.0 和 clang++ 3.6.0)时,出现以下错误:

test.cpp:9:18: error: no matching function for call to 'get'
std::cout << std::get<value>(x);
^~~~~~~~~~~~~~~
test.cpp:13:5: note: in instantiation of function template specialization 'test<std::integral_constant<unsigned long, 1> >' requested here
test(std::integral_constant<std::size_t,1>());
^~~~~~~~~~~~~~~
<skipped>

/usr/bin/../lib/gcc/x86_64-linux-gnu/5.1.0/../../../../include/c++/5.1.0/tuple:867:5: note: candidate template ignored: invalid explicitly-specified argument for template parameter '_Tp'
get(tuple<_Types...>& __t) noexcept
^

和类似的 note: 条目用于 std::get 的其他重载。

但我将 std::integral_constant 传递给 test(),这是一个常量表达式,为什么它会是一个“无效的显式指定参数”对于模板参数?是 clang 错误还是我在这里做错了什么?

我注意到,如果我将 test() 的参数从 const T& 更改为 const T,则 clang 会成功编译。通过引用传递,我是否以某种方式失去了 integral_constantconstexpr 质量?

最佳答案

由于一个星期都没有答案,我将发布我的愿景。我远不是语言专家,实际上我会认为自己是一个完整的新手,但仍然如此。以下是根据我对标准的阅读,以及我最近的 question .

所以,首先让我们按以下方式重写代码:

struct A {
constexpr operator int() const { return 42; }
};

template <int>
void foo() {}

void test(const A& value) {
foo<value>();
}

int main() {
A a{};
test(a);
}

它表现出相同的行为(使用 gcc 构建并使用 clang 失败并出现类似错误),但是:

  • test() 免于模板类型扣除, 以确保问题与类型推导无关,
  • 使用“模拟”代替 std成员确保这不是他们实现的问题,
  • 并且有一个显式变量a ,不是临时的,稍后解释。

这里发生了什么?我会引用N4296 .

我们有一个模板foo带有非类型参数。

[14.3.2(temp.arg.nontype)]/1:

A template-argument for a non-type template-parameter shall be a converted constant expression (5.20) of the type of the template-parameter.

所以模板参数,即value , 应该是 int 类型的转换常量表达式.

[5.20(expr.const)]/4:

A converted constant expression of type T is an expression, implicitly converted to type T, where the converted expression is a constant expression and the implicit conversion sequence contains only

  • user-defined conversions,
  • ... (irrelevant bullets dropped)

and where the reference binding (if any) binds directly.

我们的表达式 ( value ) 可以隐式转换为类型 int ,并且转换序列仅包含用户定义的转换。所以剩下两个问题:“转换后的表达式是否为常量表达式”和“引用绑定(bind)(如果有)是否直接绑定(bind)”。

对于第一个问题,我认为短语“转换后的表达式”表示已经转换为 int 的表达式。 ,类似于 static_cast<int>(value) ,而不是原始表达式 ( value )。为此,

[5.20(expr.const)]/2:

A conditional-expression e is a core constant expression unless the evaluation of e, following the rules of the abstract machine (1.9), would evaluate one of the following expressions:

  • ... (a long list omitted)

评估我们的表达,static_cast<int>(value) , 仅导致评估 A::operator int() ,即 constexpr ,因此是明确允许的。没有成员 A (如果有的话)被评估,其他任何东西都不被评估。

因此,static_cast<int>(value)是常量表达式。

对于第二个问题,关于引用绑定(bind),我根本不清楚这是指哪个进程。然而,无论如何,我们的代码中只有一个引用(const A& value),它直接绑定(bind)到变量a。的 main (这就是我引入 a 的原因)。

的确,直接绑定(bind)定义在[8.5.3(dcl.init.ref)]/5的末尾:

In all cases except the last (i.e., creating and initializing a temporary from the initializer expression), the reference is said to bind directly to the initializer expression.

这个“最后”案例似乎指的是 5.2,非直接绑定(bind)意味着从临时(如 const int& i = 42;)初始化,而不是我们拥有非临时 a 的情况。 .

UPD:我问了a separate question检查我对上述标准的理解是否正确。


所以底线是代码应该是有效的,clang 是错误的。我建议您将错误提交给 clang 错误跟踪器,并引用这个问题。或者,如果出于某种原因您不提交错误,请告诉我,我会提交。

UPD:归档a bug report

关于c++ - clang 中明确指定的参数无效,但在 gcc 中编译成功——谁错了?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33872039/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com