c++ 无法从不同类型的值推导出非类型模板参数

9w11ddsr  于 2023-06-25  发布在  其他
关注(0)|答案(1)|浏览(138)

我有一个设计,它触发了一个推断非类型模板参数的失败。我有以下最小的例子:

#include <array>
#include <cstdint>

// KO see below
// using NbDim_t = uint8_t;
using NbDim_t = size_t;

// let's say it's a N dimensionnal matrix
template <NbDim_t DIM>
struct Mat {
    static constexpr NbDim_t dims = DIM;
};

// this is a matrix creator from an array of size of it's different dimensions
template <NbDim_t DIM>
Mat<DIM> Create(std::array<int, DIM> input) {
    return Mat<DIM>();
}

int main() {
    std::array<int, 3> d = {1, 2, 3};
    // KO if NbDim_t si not std::array<whatever,whatever>::size_type
    // cannot deduced a non-type template parameter of one type from a value of
    // different type
    auto M = Create(d);

    return 0;
}

Playable example
由于超出这个最小示例范围的原因,我想对用于表示Mat维数的类型进行微调。
然而,如果我不使用size_tDIM就不能被推导出来,因为在调用点,它的类型是size_t,而我的模板函数期望的是NbDim_t,这是不同的,即使在编译时,编译器可以检测到转换是有效的。
1.模板推导的确切规则是什么,使这个设计错误(我找不到好的地方有template argument deduction rules)?
1.我如何修复这个设计(让NbDim_t不是size_t,并从std::array参数推导出来)?
[编辑]我可能有第二部分的解决方案:

#include <array>
#include <cstddef>
#include <cstdint>

// OK now
using NbDim_t = uint8_t;
// using NbDim_t = size_t;

// let's say it's a N dimensionnal matrix
template <NbDim_t DIM>
struct Mat {
    static constexpr NbDim_t dims = DIM;
};

// this is a matrix creator from an array of size of it's different dimensions
template <size_t N, NbDim_t DIM = N>
Mat<DIM> Create(std::array<int, N> input) {
    return Mat<DIM>();
}

int main() {
    std::array<int, 3> d = {1, 2, 3};
    // N deduced then set into DIM
    auto M = Create(d);

    return 0;
}

Live有更好的方法吗?

kgsdhlau

kgsdhlau1#

非类型模板参数是从函数参数类型的模板参数列表中推导出来的,它必须具有完全相同的类型。来自cppreference上的链接文章www.example.com https://en.cppreference.com/w/cpp/language/template_argument_deduction#Deduction_from_a_type:
如果在函数参数的模板参数列表中使用函数模板的非类型模板参数(其也是模板),并且推导出相应的模板实参,则推导出的模板实参的类型(如在其封闭的模板参数列表中指定的,意味着保留引用)必须与非类型模板参数的类型完全匹配
或从标准[温度扣除类型] p20
如果P有一个包含<i>的表单,并且如果i的类型与由封闭的 * simple-template-id * 命名的模板的对应模板参数的类型不同,则演绎失败。
下面给出这个例子:

template<int i> class A { /* ... */ };
template<short s> void f(A<s>);
void k1() {
  A<1> a;
  f(a);             // error: deduction fails for conversion from int to short
  f<1>(a);          // OK
}

所以,如果你想从std::array<int, DIM>推导出DIMDIM * 必须 * 具有std::size_t类型。
您可以简单地让size_t隐式地转换为NbDim_t

template <std::size_t DIM>
Mat<DIM> Create(std::array<int, DIM> input) {
    return Mat<DIM>();
}

相关问题