草庐IT

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

coder 2023-11-16 原文

以下代码在 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/

有关c++ - clang 中明确指定的参数无效,但在 gcc 中编译成功——谁错了?的更多相关文章

  1. ruby - 如何指定 Rack 处理程序 - 2

    Rackup通过Rack的默认处理程序成功运行任何Rack应用程序。例如:classRackAppdefcall(environment)['200',{'Content-Type'=>'text/html'},["Helloworld"]]endendrunRackApp.new但是当最后一行更改为使用Rack的内置CGI处理程序时,rackup给出“NoMethodErrorat/undefinedmethod`call'fornil:NilClass”:Rack::Handler::CGI.runRackApp.newRack的其他内置处理程序也提出了同样的反对意见。例如Rack

  2. ruby-on-rails - 如何在 ruby​​ 中使用两个参数异步运行 exe? - 2

    exe应该在我打开页面时运行。异步进程需要运行。有什么方法可以在ruby​​中使用两个参数异步运行exe吗?我已经尝试过ruby​​命令-system()、exec()但它正在等待过程完成。我需要用参数启动exe,无需等待进程完成是否有任何ruby​​gems会支持我的问题? 最佳答案 您可以使用Process.spawn和Process.wait2:pid=Process.spawn'your.exe','--option'#Later...pid,status=Process.wait2pid您的程序将作为解释器的子进程执行。除

  3. ruby-on-rails - 如何优雅地重启 thin + nginx? - 2

    我的瘦服务器配置了nginx,我的ROR应用程序正在它们上运行。在我发布代码更新时运行thinrestart会给我的应用程序带来一些停机时间。我试图弄清楚如何优雅地重启正在运行的Thin实例,但找不到好的解决方案。有没有人能做到这一点? 最佳答案 #Restartjustthethinserverdescribedbythatconfigsudothin-C/etc/thin/mysite.ymlrestartNginx将继续运行并代理请求。如果您将Nginx设置为使用多个上游服务器,例如server{listen80;server

  4. ruby - RSpec - 使用测试替身作为 block 参数 - 2

    我有一些Ruby代码,如下所示:Something.createdo|x|x.foo=barend我想编写一个测试,它使用double代替block参数x,这样我就可以调用:x_double.should_receive(:foo).with("whatever").这可能吗? 最佳答案 specify'something'dox=doublex.should_receive(:foo=).with("whatever")Something.should_receive(:create).and_yield(x)#callthere

  5. ruby-on-rails - 无法在centos上安装therubyracer(V8和GCC出错) - 2

    我正在尝试在我的centos服务器上安装therubyracer,但遇到了麻烦。$geminstalltherubyracerBuildingnativeextensions.Thiscouldtakeawhile...ERROR:Errorinstallingtherubyracer:ERROR:Failedtobuildgemnativeextension./usr/local/rvm/rubies/ruby-1.9.3-p125/bin/rubyextconf.rbcheckingformain()in-lpthread...yescheckingforv8.h...no***e

  6. ruby - 如何在 Ruby 中拆分参数字符串 Bash 样式? - 2

    我正在为一个项目制作一个简单的shell,我希望像在Bash中一样解析参数字符串。foobar"helloworld"fooz应该变成:["foo","bar","helloworld","fooz"]等等。到目前为止,我一直在使用CSV::parse_line,将列分隔符设置为""和.compact输出。问题是我现在必须选择是要支持单引号还是双引号。CSV不支持超过一个分隔符。Python有一个名为shlex的模块:>>>shlex.split("Test'helloworld'foo")['Test','helloworld','foo']>>>shlex.split('Test"

  7. ruby - 检查方法参数的类型 - 2

    我不确定传递给方法的对象的类型是否正确。我可能会将一个字符串传递给一个只能处理整数的函数。某种运行时保证怎么样?我看不到比以下更好的选择:defsomeFixNumMangler(input)raise"wrongtype:integerrequired"unlessinput.class==FixNumother_stuffend有更好的选择吗? 最佳答案 使用Kernel#Integer在使用之前转换输入的方法。当无法以任何合理的方式将输入转换为整数时,它将引发ArgumentError。defmy_method(number)

  8. ruby-on-rails - 在 ruby​​ .gemspec 文件中,如何指定依赖项的多个版本? - 2

    我正在尝试修改当前依赖于定义为activeresource的gem:s.add_dependency"activeresource","~>3.0"为了让gem与Rails4一起工作,我需要扩展依赖关系以与activeresource的版本3或4一起工作。我不想简单地添加以下内容,因为它可能会在以后引起问题:s.add_dependency"activeresource",">=3.0"有没有办法指定可接受版本的列表?~>3.0还是~>4.0? 最佳答案 根据thedocumentation,如果你想要3到4之间的所有版本,你可以这

  9. ruby-on-rails - 在默认方法参数中使用 .reverse_merge 或 .merge - 2

    两者都可以defsetup(options={})options.reverse_merge:size=>25,:velocity=>10end和defsetup(options={}){:size=>25,:velocity=>10}.merge(options)end在方法的参数中分配默认值。问题是:哪个更好?您更愿意使用哪一个?在性能、代码可读性或其他方面有什么不同吗?编辑:我无意中添加了bang(!)...并不是要询问nobang方法与bang方法之间的区别 最佳答案 我倾向于使用reverse_merge方法:option

  10. ruby - 如果指定键的值在数组中相同,如何合并哈希 - 2

    我有一个这样的哈希数组:[{:foo=>2,:date=>Sat,01Sep2014},{:foo2=>2,:date=>Sat,02Sep2014},{:foo3=>3,:date=>Sat,01Sep2014},{:foo4=>4,:date=>Sat,03Sep2014},{:foo5=>5,:date=>Sat,02Sep2014}]如果:date相同,我想合并哈希值。我对上面数组的期望是:[{:foo=>2,:foo3=>3,:date=>Sat,01Sep2014},{:foo2=>2,:foo5=>5:date=>Sat,02Sep2014},{:foo4=>4,:dat

随机推荐