Clang不编译代码,但是gcc和msvc编译了它


14

我不明白这是什么问题:在我的代码中还是在编译器中(不太可能)。有一段这样的代码:

#include <iostream>
#include <type_traits>
#include <set>


template<typename T, typename = void>
struct TestA: std::false_type {};

template<typename T>
struct TestA<T, std::void_t<typename T::reverse_iterator>> : std::true_type {};

template<typename T>
struct TestA<T, std::void_t<typename T::dummy_iterator>> : std::true_type {};

int main()
{
    std::cout << TestA<std::set<int>>::value;
}

GCC和MSVC都可以对其进行编译。我使用不同版本的GCC和MSVC 17(本地)和19在Godbolt上进行了测试。这是一个链接:https ://godbolt.org/z/Enfm6L 。

但是Clang不会编译它并发出错误:

redefinition of `'TestA<T, std::void_t<typename T::dummy_iterator> >'`

我很感兴趣-也许在标准的某些部分中这段代码是不正确的,或者还有其他地方。


怎么样“的std ::组:: reverse_iterator的”“的std ::设置:: dummy_iterator”在铛头文件中定义?
mvidelgauz

std :: set :: dummy_iterator根本没有在clang头中定义(我希望)。您可以将dummy_iterator更改为所需的任何值,并且不会更改结果,因为问题不在定义中,如下所示。
安德烈

谢谢安德烈,我读了答案,确实很有趣
mvidelgauz

Answers:


9

这很可能与CWG 1558有关

当前的17.6.7 [temp.alias]措词未指定别名模板专业化中未使用参数的处理。例如:

  #include <iostream>

  template <class T, class...>
    using first_of = T;

  template <class T>
    first_of<void, typename T::type> f(int)
      { std::cout << "1\n"; }

  template <class T>
    void f(...)
      { std::cout << "2\n"; }

  struct X { typedef void type; };

  int main() {
    f<X>(0);
    f<int>(0);
  }

T等于int时对first_of的引用仅等于void,还是替换失败?

这是一个已解决的缺陷,但是如果您使用的Clang版本尚未实现修复,它可能仍会认为这两个专业都只是将第二个参数定义为void,而不是进行整个替换失败。解决方法是不使用普通别名std::void_t,而是使用稍微复杂一些的版本

template <typename...> struct voider { using type = void; };
template <typename... T> using my_void_t = typename voider<T...>::type;

对于类模板(别名现在代表的含义),定义了替换失败。将其插入您的示例可以使Clang https://godbolt.org/z/VnkwsM令人安心。


1
另一个解决方法是为每个需求创建特征,然后将其组合为enable_ifwith std::disjunction(或
require

感谢您的帮助和参考!悲伤,就听到这种错误在锵。有趣的是,我认为您的void_t实现是标准的。无法采用模板别名的想法。
安德烈
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.