【问题标题】:Deduction guide for the template class std::valarray<T>模板类 std::valarray<T> 的推演指南
【发布时间】:2019-10-08 15:59:34
【问题描述】:

在C++标准中,模板类std::valarray&lt;T&gt;有如下推导指南:

template<class T, size_t cnt> valarray(const T(&)[cnt], size_t) -> valarray<T>;

然而,在类的构造函数中,只有以下合适的构造函数(或者我弄错了吗?)

valarray(const T&, size_t);

但是如果用类似的推导指南来运行下面的演示程序

#include <iostream>
#include <utility>

template <typename T>
struct A
{
    A( const T &, size_t ) { std::cout << "A<T>()\n"; }
};

template<class T, size_t cnt> 
A(const T(&)[cnt], size_t) -> A<T>;

int main()
{
    int a[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };

    A obj( a, std::size( a ) );
}

gcc 编译器出现错误

rog.cc:17:12: error: invalid conversion from 'int*' to 'int' [-fpermissive]
   17 |     A obj( a, std::size( a ) );
      |            ^
      |            |
      |            int*
prog.cc:7:8: note:   initializing argument 1 of 'A<T>::A(const T&, size_t) [with T = int; size_t = long unsigned int]'
    7 |     A( const T &, size_t ) { std::cout << "A<T>()\n"; }
      |        ^~~~~~~~~

所以出现了一个问题,它是 C++ 标准的缺陷,还是编译器的错误,或者我遗漏了什么。

【问题讨论】:

    标签: c++ class c++17 type-deduction construct


    【解决方案1】:

    使用https://en.cppreference.com/w/cpp/numeric/valarray/deduction_guides给出的例子,我们可以看看编译器输出没有优化,看看调用了哪个构造函数:

    int a[] = {1, 2, 3};
    std::valarray va(a, 3);
    

    https://godbolt.org/z/rtgeoi

    main:
        [...]
        call    std::valarray<int>::valarray(int const*, unsigned long)
        [...]
    

    C++ 数组很容易衰减为指向其第一个元素的指针。但是,如果没有推导指南,则从隐式指南推导的类型将是 std::valarray&lt;int[3]&gt;(从 valarray(const T&amp;, size_t) 生成的指南获胜,因为它不需要数组到指针的转换)。如果我们同时拥有 A(const T&amp;, std::size_t);A(const T*, std::size_t); 构造函数,这可以在您的示例中得到证明:

    template <typename T>
    struct A
    {
        A(const T&, std::size_t);
        A(const T*, std::size_t);
    };
    
    int main()
    {
        int a[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
        A obj(a, 10);
    }
    
    // Result:
        call    A<int [10]>::A(int const (&) [10], unsigned long)
    

    https://godbolt.org/z/nlFlVT

    添加演绎指南正确演绎出预期的int而不是int[10]https://godbolt.org/z/efj557

    【讨论】:

    • 问题是代码没有使用 C++ gcc HEAD 10.0.0 20190 编译,正如我在问题中指出的那样。如果要添加带有指针类型参数的第二个构造函数,则选择此构造函数。
    • 您问题中的代码无法编译,因为用户定义的推导指南与唯一的构造函数相矛盾。 A&lt;int&gt;::A(const int&amp;, size_t) 构造函数不能将 int[10] 作为第一个参数。您需要构造函数和推导指南(valarray 有什么,这样你就不会意外推导出 A&lt;int[10]&gt; 因为const T&amp; 推演击败const T*),或者只需要来自指针的构造函数(那么你不能从count相同值的副本,但您不需要用户定义的扣除指南)。
    • 即使有两个构造函数,构造函数 A( const T *, size_t ) 也会被选中。
    • @VladfromMoscow 使用演绎指南,这就是目的(并制作代码compile)。如果你的意思是没有推导指南,那么我 cannot reproduce 那...你能显示你得到这个的确切的两个构造函数代码、编译器版本和标志吗(最好在 Godbolt 上)?
    【解决方案2】:

    然而,在类的构造函数中,只有以下合适的构造函数(或者我弄错了吗?)

    还有这个:

    valarray( const T* vals, std::size_t count );
    

    当你传入的数组衰减到一个指针时,哪个匹配,允许 cppreference examplecompile

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2018-02-16
      • 2019-04-15
      • 2019-09-23
      • 1970-01-01
      • 2023-04-04
      • 2021-06-20
      相关资源
      最近更新 更多