延迟模板实例化中的编译器分歧

问题描述 投票:0回答:1

当我的基类没有实现成员函数时,我想触发

static_assert

#include<type_traits>
  
template<typename T>
struct AlwaysFalse : public std::false_type {};

struct B
{
  template<typename S>
  void foo(){}
};

template <typename T,typename S>
struct A:T
{
  auto foo(){
    if constexpr (requires{T::template foo<S>();})
    return 1;
    else
       static_assert(AlwaysFalse<A>::value,
                    "foo is not implemented.");
  }
};

int main()
{
A<B,double> a;
a.foo();
}

这可以在 gcc 12.2 中编译,但无法使用 clang 16 和 clang trunk 进行编译。 如果成员函数

foo
不是模板,clang 也会编译它。

这里哪个编译器是正确的?我想是GCC,因为基类成员函数在那里并且它不应该读取

AlwaysFalse
我的代码是否符合 C++ 标准?

我还有一个解决方法,通过在需要表达式中创建一个对象

if constexpr (requires(T t){t. template foo<S>();})

这两个编译器都会再次编译。

GodBolt 模板版本:https://godbolt.org/z/oTWPhWE99

GodBolt 非模板版本:https://godbolt.org/z/7b5xcvYYv

GodBolt 解决方法:https://godbolt.org/z/6Taj7c515

c++ gcc clang language-lawyer
1个回答
0
投票

首先,正确的大写是“Godbolt”。该网站以其创建者 Matt Godbolt 的名字命名。

我们可以通过将代码简化为:

来验证实现分歧确实与编译器认为应该实例化 
if constexpr

的子语句无关。
struct B
{
  template<typename S>
  void foo(){}
};

template <typename T,typename S>
struct A : T
{
  auto foo(){
    static_assert(requires{T::template foo<S>();});
  }
};

int main()
{
    A<B,double> a;
    a.foo();
}

在这里我们再次看到只有 Clang 有问题。但是,如果您在

T::template foo<S>();
的主体中确实有语句
A::foo
,那么 Clang 就没有问题,所以显然 Clang 并不认为它实际上是格式错误的。这意味着
requires
表达式应该为 true。结论:Clang bug。

© www.soinside.com 2019 - 2024. All rights reserved.