std :: declare_if或在编译时丢弃成员声明的其他假设方法

时间:2019-06-13 17:13:51

标签: c++ c++17 sfinae c++20

SFINAE对于丢弃函数体非常有用,但是为什么不能将其用于丢弃成员变量?

是否计划在某个时候将这种功能添加到现代C ++中?我尝试使用std::enable_ifstd::conditional(如果允许其大小为零,则可以使用,但是可能会破坏其他所有内容)。

我希望能够使用如下假设的SFINAE模式生成别名:

template<class T, SIZE> 
struct Vector {
    union {
        T mArray[SIZE] = {};
        struct {
            std::declare_if<SIZE >= 1, T>::type x;
            std::declare_if<SIZE >= 2, T>::type y;
            std::declare_if<SIZE >= 3, T>::type z;
        };
    };
};

除了缺乏编译器支持之外,我目前没有任何充分的理由使该原因不存在。 如果您有一个优雅的解决方法或解决方案的想法,而无需在联合中增加其他大小,也无需编写样板代码(例如基数),然后进行部分专业的派生。 我很想知道。

2 个答案:

答案 0 :(得分:3)

借助属性[[no_unique_address]],您几乎可以实现所需的目标,

  

指示此数据成员不必具有与该类的所有其他非静态数据成员不同的地址。这意味着,如果成员具有空类型(例如,无状态的分配器),则编译器可以对其进行优化以使其不占用空间。

适用于您的用例:

constant M : integer := 3;

constant N : integer := 8;

constant Nminus1 : integer := 7;

constant TwoPiN : real := 2.0*MATH_PI/real(N);

Butterfly code : 

 TempRe := xtmp(kNs).re *WCos - xtmp(kNs).re * WSin;

 TempIm := xtmp(kNs).im*WCos + xtmp(kNs).im*Wsin;

 xtmp(kNs).re := xtmp(k).re - TempRe;

 xtmp(kNs).im := xtmp(k).im - TempIm;

 xtmp(k).re := xtmp(k).re + TempRe;

 xtmp(k).im := xtmp(k).im + TempIm;


 Main:process(x_in)

 variable Ns, count ,Stage, k, kNs, p ,p_int, M1: integer;

 variable Wcos, Wsin : real;

 variable x : complexArr;


 begin

 x := x_in; --copy insignal

 Ns := N; 

 M1 := M;

 count := 0;


 for Stage in 1 to M loop

 k := 0;

 Ns := Ns/2; --index distance between a dual node pair

 M1 := M1 - 1;


  while(k< N) loop


 for n in 1 to Ns loop

 p := Digit_Reverse(k/2**(M-1));


 Wcos := cos(TwoPiN*real(p));--W to the power of p


 Wsin := - sin(TwoPiN*real(p)); --W = exp(\u2212 j2\u03c0/N)


 kNs := k + Ns;

 Butterfly(x,k,kNs,Wcos,Wsin);

 k := k + 1;

 count := count +1;

 end loop;

 k := k + Ns;

 end loop;

 end loop;

 Unscramble(x); --output

 x_ut <= x;

在这里,我将#include <type_traits> template <typename T, int SIZE> struct Vector { T x; [[no_unique_address]] std::conditional_t<(SIZE > 1), T, decltype([]{})> y; [[no_unique_address]] std::conditional_t<(SIZE > 2), T, decltype([]{})> z; }; int main() { static_assert(sizeof(Vector<double, 1>) == 1 * sizeof(double)); static_assert(sizeof(Vector<double, 2>) == 2 * sizeof(double)); static_assert(sizeof(Vector<double, 3>) == 3 * sizeof(double)); } 用作空类型,产生了不同的类型,以便它们可以共享相同的地址。

答案 1 :(得分:2)

目前无法实现,但是您可以编写一个模板化的get()函数来接受整数值。另外,如果您使用的是C ++ 17,则也可以使用结构化绑定。

#include <tuple>
#include <iostream>

// not elegant way of naming as enum will polute the whole namespace where it is defined
enum Idx {
    X = 0,
    Y = 1,
    Z = 2,
    W = 3,
    R = 0,
    G = 1,
    B = 2,
    A = 3
};

template <typename T, std::size_t SIZE>
struct Vector
{
    template<std::size_t Index>
    T& get() {
        static_assert(Index < SIZE, "Invalid Index");
        return data[Index];
    }

    template<std::size_t Index>
    const T& get() const noexcept {
        static_assert(Index < SIZE, "Invalid Index");
        return data[Index];
    }

    T data[SIZE];
};

//only needed if structured binding is required
namespace std {
template<typename T, size_t SIZE>
struct tuple_size<Vector<T, SIZE>> {
    constexpr static size_t value = SIZE;
};

template<typename T, size_t I, size_t SIZE>
struct tuple_element<I, Vector<T, SIZE>> {
    using type = T;
};
}

int main()
{
  Vector<int, 2> value = {0, 1};
  std::cout << "x = " << value.get<X>() << ": y = " << value.get<Y>() << '\n';

  // structured binding, available only in C++17
  auto& [x, y]  = value;
  std::cout << "x = " << x << ": y = " << y << '\n';

  // will generate a compiler error
  //auto& [x1, y1, z1] = value;

  // will invoke the static assert
  //auto z = value.get<Z>();
  return 0;
}