SFINAE 工作正常,但概念约束在类模板实例化中进行了模糊的推论

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

我正在编写一个曲线类,它可以采用算术类型或算术数组类型作为模板参数。 对于算术数组曲线,本身需要一个包含不同维度算术曲线的数组成员。 在尝试使用概念作为模板约束后,以下代码可能会导致错误的 sizeof 计算(可能是由错误的类型推导引起的)。 还有其他三种方法可以纠正编译器错误的数组大小

#include <vector>
#include <array>
#include <iostream>


template<typename T>
concept Arithmetic = std::is_arithmetic<T>::value;

template<typename U>
using arithmetic_enable_if_t = std::enable_if_t<std::is_arithmetic_v<U>>;


template<typename>
struct get_array_size;

template<typename T, size_t Size>
struct get_array_size<std::array<T, Size>> {
    static constexpr size_t size = Size;
};

template<typename T, typename U = T::value_type>
concept ArithmeticArray = std::is_same<T, std::array<U, get_array_size<T>::size>>::value and Arithmetic<U>;

template<typename U>
using arithmetic_array_enable_if_t = std::enable_if_t<std::is_same_v<U, std::array<typename U::value_type, get_array_size<U>::size>>&& std::is_arithmetic_v<typename U::value_type>>;


// template<typename T, typename Enable = void>  // solution 3
template<typename T>
class Curve {};

// template<typename T>  // solution 3
// class Curve<T, arithmetic_enable_if_t<T>> {  // solution 3
template<typename T> requires (Arithmetic<T>)
class Curve<T> {
// class ACurve {  // solution 2
public:
    int _;
};

// template<typename T>  // solution 3
// class Curve<T, arithmetic_array_enable_if_t<T>> {  // solution 3
template<typename T> requires (ArithmeticArray<T>)
class Curve<T> {
public:
    std::array<Curve<typename T::value_type>, 1> internal_curves;

    // std::array<Curve<float>, 1> internal_curves;  // solution 1

    // std::array<ACurve<typename T::value_type>, 1> internal_curves;  // solution 2
};


int main(){
    Curve<std::array<float, 1>> curve;
    std::cout << sizeof(curve.internal_curves) << std::endl;

    return 0;
}

原代码打印internal_curves sizeof 1并且无法调试,这只是一个类头位。 其他 3 个解决方案都可以正常工作,同时显示 4 的大小

  1. 手动专门化internal_curves类型
  2. 将算术曲线类型更改为不同的类名
  3. 使用enable_if_t代替概念

环境:

_MSC_版本:1939 标准:C++20

参考其他发布的答案后,例如: C++20 概念是否取代其他形式的约束? 概念是 SFINAE 的变体吗

我觉得在使用 require 时它可能会以递归方式损坏编译器 但如何呢? 如果有人能告诉的话,不胜感激

templates visual-c++ sizeof sfinae c++-concepts
1个回答
0
投票

连续使用c++三天大概就知道原因了。

替换失败时SFINAE停止,替换完成后需要检查。

这里发生的事情是,在实例化 ArithmeticArrayCurve 时,由于在所有操作完成后进行了 require 子句检查,它不断地尝试将自己替换为成员,而不会停止。

使用SFINAE,可以轻松停止该成员的ArithmeticArratCurve扣除,即停止递归。

此外,使用 self 模板意味着潜在的递归,这是危险的。它必须通过编译行为来避免,这表明编码器在使用除requires之外的自模板时需要确保具有其他停止推演机制的推演

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