Clang和GCC在自动指定器中不赞成在C ++ 17中使用非类型模板参数 [英] Clang and GCC disagree in auto specifier for non-type template parameter in a casting C++17

查看:201
本文介绍了Clang和GCC在自动指定器中不赞成在C ++ 17中使用非类型模板参数的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我基本上有一个依赖于非类型模板参数的类。我定义了一个转型,因此非类型模板参数 N 的对象可以转换为另一个 M 。我有一个最小的例子可以重现这种情况:

  template< auto Integral> 
class Test {
public:
typedef decltype(Integral)value_type;
static constexpr value_type N =积分;

constexpr测试(const value_type& x = 0);

模板< auto Integral2>
constexpr显式运算符Test< Integral2>()const;
private:
value_type n;
};

模板< auto Integral>
constexpr Test< Integral> :: Test(const value_type& x){
if(x <0){
n = N - ( - x)%N;
}
else {
n = x%N;
}
}

模板< auto Integral>模板< auto Integral2>
constexpr Test< Integral> :: operator Test< Integral2>()const {
return Test< Integral2>(n%(Test< Integral2> :: N));
}

我在Ubuntu中使用GCC 7.2.0和Clang 5.0.0进行编译16.04 LTS的标志 -O2 -std = c ++ 17



问题在于我正在编译所有的时间使用g ++和一切按预期工作,但后来我尝试了clang ++来检查是否一切仍然编译罚款。



令我惊讶的是,情况并非如此,因为铿锵++抱怨g ++没有的某些部分。您可以在编译器资源管理器中查看差异视图。



clang ++产生的错误信息之一是:

 错误:'operator Test< 'Integral2>'与'Test< Integral>'中的任何声明都不匹配

这个让我觉得铿锵声++没有找到正确的转换声明,但我不知道。



注意:仅出现此第一个错误将声明与定义分开时。否则,这似乎是正确的。



这是clang ++产生的第二个错误:

 错误:非类型模板参数不能有'auto'

这个更令我惊讶,因为错误告诉我们应该在C ++ 17中有效。可能我在这里错过了一些东西,因为这对我没有意义。



请记住,第二个错误仅出现在此转换的情况下。实际代码中的任何地方都会给出错误(即使还有更多 auto 非类型模板参数)。



在这一点上,我有一些问题:


  • 在clang编译器中产生错误是什么?

  • 根据标准,哪一个是正确的?
  • 是一个铿锵虫。这里有一个简短的再现:

      template< int A> 
    struct X {
    template< auto B>
    X< B> FOO();
    };

    模板< int A>
    模板< auto B>
    X< B> X< A> :: foo(){
    return {};

    $ / code>

    如果 auto B int B 取代,clang接受它。 gcc按原样接受它。对于clang,这只是嵌套的模板声明的问题。没有任何关于 auto 作为占位符模板的非类型参数,它会阻止它被用于非线性定义某些内容。



    在提交新的clang错误时,我发现 35655 ,甚至更短的再现:

     模板< typename> 
    struct S {
    template< auto n>
    static void f(){
    + n;
    }
    };

    不符合:

      source.cpp:5:3:错误:无效参数类型'auto'为一元表达式
    + n;


    I basically have a class that depends on a non-type template parameter. I defined a casting so an object of non-type template parameter N can convert to another of M. I have a minimal example that can reproduce the situation:

    template<auto Integral>
    class Test{
        public:
            typedef decltype(Integral) value_type;
            static constexpr value_type N = Integral;
    
            constexpr Test (const value_type& x = 0);
    
            template<auto Integral2>
            constexpr explicit operator Test<Integral2>() const;
        private:
            value_type n;
    };
    
    template<auto Integral>
    constexpr Test<Integral>::Test (const value_type& x){
        if (x < 0){
            n = N - (-x)%N;
        }
        else{
            n = x%N;
        }
    }
    
    template<auto Integral> template<auto Integral2>
    constexpr Test<Integral>::operator Test<Integral2>() const{
        return Test<Integral2>(n%(Test<Integral2>::N));
    }
    

    I'm compiling using GCC 7.2.0 and Clang 5.0.0 in Ubuntu 16.04 LTS with the flags -O2 -std=c++17.

    The problem is that I was compiling all the time using g++ and everything worked as expected, but then I tried clang++ to check if everything was still compiling fine.

    To my surprise, that wasn't the case, as clang++ complained about some parts that g++ didn't. You can check a diff view in Compiler Explorer.

    One of the error messages that clang++ produces is:

    error: out-of-line definition of 'operator Test<Integral2>' does not match any declaration in 'Test<Integral>'
    

    This one makes me think that clang++ didn't find a "right" declaration of the conversion, but I don't know.

    Note: This first error only appears when separating the declaration from the definition. Otherwise, it seems to be correct.

    This is the second error that clang++ produces:

    error: a non-type template parameter cannot have type 'auto'
    

    But this one surprises me even more because the error tells something that is supposed to be valid in C++17. Probably I'm missing something here because this just doesn't make sense to me.

    Keep in mind that this second error only appears in the case of this conversion. Anywhere in the actual code gives the error (even though there are many more auto non-type template parameters).

    At this point, I have some questions:

    • What is producing the error in the case of the clang compiler?
    • Which one is correct, according to the standard?

    解决方案

    This is a clang bug. Here's a short reproduction:

    template <int A>
    struct X {
        template <auto B>
        X<B> foo();
    };
    
    template <int A>
    template <auto B>
    X<B> X<A>::foo() {
        return {};
    }
    

    If auto B is replaced by int B, clang accepts it. gcc accepts it as-is. For clang, this is only a problem with the nested template declarations. There's nothing about auto as a placeholder template non-type parameter that would prevent it from being used to define something out-of-line.

    While filing a new clang bug, I found 35655, with an even shorter reproduction:

    template<typename>
    struct S {
        template<auto n>
        static void f() {
            +n;
        }
    };
    

    which fails with:

    source.cpp:5:3: error: invalid argument type 'auto' to unary expression
                    +n;
    

    这篇关于Clang和GCC在自动指定器中不赞成在C ++ 17中使用非类型模板参数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆