首页 > 解决方案 > 避免在 C++17 中为每个联合样式类编写构造函数

问题描述

我在一个项目中坚持使用 c++17,所以我无权访问指定的初始化程序。我有一堆联合类型,我想避免以这种方式初始化(​​因为它很烦人):

MyUnionType x;
x.value = value_set_for_all_union_members;

我想要这个

MyUnionType x(value_set_for_all_union_members); 

但我也想避免为我创建的每个联合编写实现。我知道我所有的联合类型都将具有以下结构,每个联合都意味着实际上代表位字段,所以我实际上确实想要在这里进行类型修剪,我知道根据 C++ 它是“UB”,但是在 C++ 委员会中,在 C 中它不是未定义的行为,因此我关心的所有编译器都会在这里做我想做的事。

union Example{
    integer_type value;
    custom_safe_bitfield_abstraction<...> a;
    custom_safe_bitfield_abstraction<...> b;
    ...
};

我想,好吧,我就继承构造函数,并使用 CRTP 提取适当的integer_type. 当然我不能直接继承联合,所以我选择了这个策略:

struct Example : Base<Example>{
    union{
        integer_type value;
        custom_safe_bitfield_abstraction<...> a;
        custom_safe_bitfield_abstraction<...> b;
        ...
    };
};

使用匿名联合,我应该能够以与以前相同的方式使用它(example.value 应该是联合内部的值)。

然后在实现中我执行以下操作:

template<class Derived_T>
struct Base{
    using value_type = decltype(Derived_T::value); 
    explicit Base(value_type v){
        static_cast<Derived_T*>(this)->value = v; 
    }
}

然而这不起作用:

error: Incomplete type 'Example' used in nested name specifier
>    using value_type = decltype(Derived_T::value); 

显然,我们不允许在声明成员之前引用它。好的...但是必须有某种方法可以将类型数据提取出来,毕竟我不关心任何内存对齐或任何事情。

我能想到的唯一另一件事是在 CRTP 模板参数(即Base<Derived_T, value_type>)中包含类型,但我想避免这样做。我想有一些方法可以在每个派生类上编写函数或指定内部类型,我也不想这样做(并且有点违背了我正在做的事情的目的)。

有没有办法避免为每个类编写构造函数,并且不牺牲我拥有的其他代码重复最小化目标?

标签: c++templatesc++17unionscrtp

解决方案


不完全是你问的......但你可以使用你可以在成员函数内部使用类型的事实D::value......所以在模板构造函数上使用 SFINAE......

我的意思是,你可以写一些东西

template <typename D>
struct Base
 {
   template <typename T>
   static constexpr bool is_value_type ()
    { return std::is_same_v<decltype(D::value), T>; }

   template <typename T, bool B = is_value_type<T>(),
             std::enable_if_t<B, int> = 0>
   explicit Base (T v)
    { static_cast<D*>(this)->value = v; }
 };

仅当推导的参数类型与B::value.

还记得添加using

using Base<Example>::Base;

里面Example

下面是一个完整的编译示例

#include <type_traits>

template <typename D>
struct Base
 {
   template <typename T>
   static constexpr bool is_value_type ()
    { return std::is_same_v<decltype(D::value), T>; }

   template <typename T, bool B = is_value_type<T>(),
             std::enable_if_t<B, int> = 0>
   explicit Base (T v)
    { static_cast<D*>(this)->value = v; }
 };

struct Example : Base<Example>
 {
   using Base<Example>::Base;

   union
    {
      long value;
      long a;
      long b;
    };
 };

int main ()
 {
   //Example  e0{0};   // compilation error
   Example  e1{1l};    // compile
   //Example  e2{2ll}; // compilation error
 }

推荐阅读