C++17完整导引-模板特性之扩展的using声明


using声明 扩展之后可以支持逗号分隔的名称列表,这个特性也可以用于参数包。
例如,你现在可以这么写:

#include <iostream>

using namespace std;

class Base {
    
    
   public:
    void a() {
    
     cout << " call a()" << endl; }
    void b() {
    
     cout << " call b()" << endl; }
    void c() {
    
     cout << " call c()" << endl; }
};

class Derived : private Base {
    
    
   public:
    using Base::a, Base::b, Base::c;
};

int main() {
    
    
    Derived d;
    d.a();
    d.b();
    d.c();
}

运行结果如下:

 call a()
 call b()
 call c()

预处理代码如下:

#include <iostream>

using namespace std;

class Base
{
    
    
  public: 
  inline void a()
  {
    
    
    std::operator<<(std::cout, " call a()").operator<<(std::endl);
  }
  
  inline void b()
  {
    
    
    std::operator<<(std::cout, " call b()").operator<<(std::endl);
  }
  
  inline void c()
  {
    
    
    std::operator<<(std::cout, " call c()").operator<<(std::endl);
  }
  
  // inline constexpr Base() noexcept = default;
};
class Derived : private Base
{
    
    
  
  public: 
  using Base::a;
  // inline void Base::a();
  
  using Base::b;
  // inline void Base::b();
  
  using Base::c;
  // inline void Base::c();
  
  // inline constexpr Derived() noexcept = default;
};
int main()
{
    
    
  Derived d = Derived();
  static_cast<Base&>(d).a();
  static_cast<Base&>(d).b();
  static_cast<Base&>(d).c();
  return 0;
}

C++17之前,你需要使用3个using声明分别进行声明。

使用变长的using声明

逗号分隔的using声明允许你在泛型代码中从可变数量的所有基类中派生同一种运算
这项技术的一个很酷的应用是创建一个重载的lambda的集合。通过如下定义:

// 继承所有基类里的函数调用运算符
template<typename... Ts>
struct overload : Ts...
{
    
    
    using Ts::operator()...;
};
// 基类的类型从传入的参数中推导
template<typename... Ts>
overload(Ts...) -> overload<Ts...>;

你可以像下面这样重载两个lambda

auto twice = overload {
    
    
                 [](std::string& s) {
    
     s += s; },
                 [](auto& v) {
    
     v *= 2; }
             };

这里,我们创建了一个overload类型的对象,并且提供了推导指引来根据lambda的类型推导出overload的基类的类型。还使用了聚合体初始化来调用每个lambda生成的闭包类型的拷贝构造函数来初始化基类子对象。上例中的using声明使得overload类型可以同时访问所有子类中的函数调用运算符。如果没有这个using声明,两个基类会产生同一个成员函数operator()的重载,这将会导致歧义。最后,如果你传递一个字符串参数将会调用第一个重载,其他类型(操作符*=有效的类型)将会调用第二个重载:

int i = 42;
twice(i);
std::cout << "i: " << i << '\n';    // 打印出:84
std::string s = "hi";
twice(s);
std::cout << "s: " << s << '\n';    // 打印出:hihi

运行结果:

i: 84
s: hihi

预处理代码如下:

#include <iostream>

using namespace std;

template<typename ... Ts>
struct overload : public Ts...
{
    
    
  using Ts::operator()...;
};

/* First instantiated from: insights.cpp:13 */
#ifdef INSIGHTS_USE_TEMPLATE
template<>
struct overload<__lambda_13_23, __lambda_13_55> : public __lambda_13_23, public __lambda_13_55
{
    
    
  using __lambda_13_23::operator();
  // inline /*constexpr */ void ::operator()(std::basic_string<char, std::char_traits<char>, std::allocator<char> > & s) const;
  
  using __lambda_13_55::operator();
  template<class type_parameter_0_0>
  inline /*constexpr */ auto ::operator()(type_parameter_0_0 & v) const
  {
    
    
    v = static_cast<type_parameter_0_0>(static_cast<<dependent type>>(v) * 2);
  }
  
  #ifdef INSIGHTS_USE_TEMPLATE
  template<>
  inline /*constexpr */ void ::operator()<int>(int & v) const
  {
    
    
    v = static_cast<int>(v * 2);
  }
  #endif
  #ifdef INSIGHTS_USE_TEMPLATE
  template<>
  inline /*constexpr */ auto ::operator()<std::basic_string<char, std::char_traits<char>, std::allocator<char> > >(std::basic_string<char, std::char_traits<char>, std::allocator<char> > & v) const;
  #endif
  
  
};
#endif

template <typename... Ts>
overload(Ts...) -> overload<Ts...>;

/* First instantiated from: insights.cpp:13 */
#ifdef INSIGHTS_USE_TEMPLATE
template<>
overload(__lambda_13_23 __0, __lambda_13_55 __1) -> overload<__lambda_13_23, __lambda_13_55>;
#endif

class __lambda_13_23
{
    
    
  public: 
  inline /*constexpr */ void operator()(std::basic_string<char, std::char_traits<char>, std::allocator<char> > & s) const
  {
    
    
    s.operator+=(s);
  }
  
  using retType_13_23 = void (*)(std::string &);
  inline constexpr operator retType_13_23 () const noexcept
  {
    
    
    return __invoke;
  };
  
  private: 
  static inline /*constexpr */ void __invoke(std::basic_string<char, std::char_traits<char>, std::allocator<char> > & s)
  {
    
    
    __lambda_13_23{
    
    }.operator()(s);
  }
  
  public: 
  // inline /*constexpr */ __lambda_13_23(__lambda_13_23 &&) noexcept = default;
  // /*constexpr */ __lambda_13_23() = default;
  
};

class __lambda_13_55
{
    
    
  public: 
  template<class type_parameter_0_0>
  inline /*constexpr */ auto operator()(type_parameter_0_0 & v) const
  {
    
    
    v = static_cast<type_parameter_0_0>(static_cast<<dependent type>>(v) * 2);
  }
  
  #ifdef INSIGHTS_USE_TEMPLATE
  template<>
  inline /*constexpr */ void operator()<int>(int & v) const
  {
    
    
    v = static_cast<int>(v * 2);
  }
  #endif
  
  #ifdef INSIGHTS_USE_TEMPLATE
  template<>
  inline /*constexpr */ auto operator()<std::basic_string<char, std::char_traits<char>, std::allocator<char> > >(std::basic_string<char, std::char_traits<char>, std::allocator<char> > & v) const;
  #endif
  
  private: 
  template<class type_parameter_0_0>
  static inline /*constexpr */ auto __invoke(type_parameter_0_0 & v)
  {
    
    
    return __lambda_13_55{
    
    }.operator()<type_parameter_0_0>(v);
  }
  public: 
  // inline /*constexpr */ __lambda_13_55(__lambda_13_55 &&) noexcept = default;
  // /*constexpr */ __lambda_13_55() = default;
  
};

overload<__lambda_13_23, __lambda_13_55> twice = overload{
    
    __lambda_13_23(__lambda_13_23{
    
    }), __lambda_13_55(__lambda_13_55{
    
    })};

int main()
{
    
    
  int i = 42;
  twice.operator()(i);
  std::operator<<(std::operator<<(std::cout, "i: ").operator<<(i), '\n');
  std::basic_string<char, std::char_traits<char>, std::allocator<char> > s = std::basic_string<char, std::char_traits<char>, std::allocator<char> >("hi", std::allocator<char>());
  twice.operator()(s);
  std::operator<<(std::operator<<(std::operator<<(std::cout, "s: "), s), '\n');
  return 0;
}

这项技术的另一个应用是std::variant访问器,如下:

扫描二维码关注公众号,回复: 16185143 查看本文章
#include <iomanip>
#include <iostream>
#include <string>
#include <type_traits>
#include <variant>
#include <vector>

// 要观览的变化体
using var_t = std::variant<int, long, double, std::string>;

// 观览器 #3 的辅助常量
template <class>
inline constexpr bool always_false_v = false;

// 观览器 #4 的辅助类型
template <class... Ts>
struct overloaded : Ts... {
    
    
    using Ts::operator()...;
};
// 显式推导指引(C++20 起不需要)
template <class... Ts>
overloaded(Ts...) -> overloaded<Ts...>;

int main() {
    
    
    std::vector<var_t> vec = {
    
    10, 15l, 1.5, "hello"};

    for (auto&& v : vec) {
    
    
        // 1. void 观览器,仅为它的副作用而调用
        std::visit([](auto&& arg) {
    
     std::cout << arg; }, v);

        // 2. 返回值的观览器,返回另一 variant 的常见模式
        var_t w = std::visit([](auto&& arg) -> var_t {
    
     return arg + arg; }, v);

        // 3. 类型匹配观览器:以不同方式处理每个类型的 lambda
        std::cout << " 翻倍后,变化体持有";
        std::visit(
            [](auto&& arg) {
    
    
                using T = std::decay_t<decltype(arg)>;
                if constexpr (std::is_same_v<T, int>)
                    std::cout << "值为 " << arg << " 的 int\n";
                else if constexpr (std::is_same_v<T, long>)
                    std::cout << "值为 " << arg << " 的 long\n";
                else if constexpr (std::is_same_v<T, double>)
                    std::cout << "值为 " << arg << " 的 double\n";
                else if constexpr (std::is_same_v<T, std::string>)
                    std::cout << "值为 " << std::quoted(arg)
                              << " 的 std::string\n";
                else
                    static_assert(always_false_v<T>, "观览器无法穷尽类型!");
            },
            w);
    }

    for (auto&& v : vec) {
    
    
        // 4. 另一种类型匹配观览器:有三个重载的 operator() 的类
        // 注:此情况下 '(auto arg)' 模板 operator() 将绑定到 'int' 与 'long',
        //    但它不存在时 '(double arg)' operator() *也会* 绑定到 'int' 与
        //    'long', 因为两者均可隐式转换到
        //    double。使用此形式时应留心以正确处理隐式转换。
        std::visit(
            overloaded{
    
    
                [](auto arg) {
    
     std::cout << arg << ' '; },
                [](double arg) {
    
     std::cout << std::fixed << arg << ' '; },
                [](const std::string& arg) {
    
    
                    std::cout << std::quoted(arg) << ' ';
                },
            },
            v);
    }
}

运行结果如下:

10 翻倍后,变化体持有值为 20 的 int
15 翻倍后,变化体持有值为 30 的 long
1.5 翻倍后,变化体持有值为 3 的 double
hello 翻倍后,变化体持有值为 "hellohello" 的 std::string
10 15 1.500000 "hello" 

预处理代码如下:

#include <iomanip>
#include <iostream>
#include <string>
#include <type_traits>
#include <variant>
#include <vector>
 
// the variant to visit
using var_t = std::variant<int, long, double, std::basic_string<char> >;

 
// helper constant for the visitor #3


template<class type_parameter_0_0>
inline constexpr const bool always_false_v = false;
 
// helper type for the visitor #4
template<class ... Ts>
struct overloaded : public Ts...
{
    
    
  using Ts::operator()...;
};

/* First instantiated from: insights.cpp:54 */
#ifdef INSIGHTS_USE_TEMPLATE
template<>
struct overloaded<__lambda_55_13, __lambda_56_13, __lambda_57_13> : public __lambda_55_13, public __lambda_56_13, public __lambda_57_13
{
    
    
  using __lambda_55_13::operator();
  template<class type_parameter_0_0>
  inline /*constexpr */ auto ::operator()(type_parameter_0_0 arg) const
  {
    
    
    (std::cout << arg) << ' ';
  }
  
  #ifdef INSIGHTS_USE_TEMPLATE
  template<>
  inline /*constexpr */ void ::operator()<int>(int arg) const
  {
    
    
    std::operator<<(std::cout.operator<<(arg), ' ');
  }
  #endif
  
  
  #ifdef INSIGHTS_USE_TEMPLATE
  template<>
  inline /*constexpr */ void ::operator()<long>(long arg) const
  {
    
    
    std::operator<<(std::cout.operator<<(arg), ' ');
  }
  #endif
  
  
  #ifdef INSIGHTS_USE_TEMPLATE
  template<>
  inline /*constexpr */ auto ::operator()<double>(double arg) const;
  #endif
  
  
  #ifdef INSIGHTS_USE_TEMPLATE
  template<>
  inline /*constexpr */ auto ::operator()<std::basic_string<char> >(std::basic_string<char> arg) const;
  #endif
  
  
  using __lambda_56_13::operator();
  // inline /*constexpr */ void ::operator()(double arg) const;
  
  using __lambda_57_13::operator();
  // inline /*constexpr */ void ::operator()(const std::basic_string<char> & arg) const;
  
  // inline constexpr overloaded<__lambda_55_13, __lambda_56_13, __lambda_57_13> & operator=(const overloaded<__lambda_55_13, __lambda_56_13, __lambda_57_13> &) /* noexcept */ = delete;
  // inline constexpr overloaded<__lambda_55_13, __lambda_56_13, __lambda_57_13> & operator=(overloaded<__lambda_55_13, __lambda_56_13, __lambda_57_13> &&) /* noexcept */ = delete;
};

#endif

// explicit deduction guide (not needed as of C++20)
template<class... Ts>
overloaded(Ts...) -> overloaded<Ts...>;

 
 /* First instantiated from: insights.cpp:54 */
 #ifdef INSIGHTS_USE_TEMPLATE
 template<>
 overloaded(__lambda_55_13 __0, __lambda_56_13 __1, __lambda_57_13 __2) -> overloaded<__lambda_55_13, __lambda_56_13, __lambda_57_13>;
 #endif
  
int main()
{
    
    
  std::vector<std::variant<int, long, double, std::basic_string<char> >, std::allocator<std::variant<int, long, double, std::basic_string<char> > > > vec = std::vector<std::variant<int, long, double, std::basic_string<char> >, std::allocator<std::variant<int, long, double, std::basic_string<char> > > >{
    
    std::initializer_list<std::variant<int, long, double, std::basic_string<char> > >{
    
    std::variant<int, long, double, std::basic_string<char> >(10), std::variant<int, long, double, std::basic_string<char> >(15L), std::variant<int, long, double, std::basic_string<char> >(1.5), std::variant<int, long, double, std::basic_string<char> >("hello")}, std::allocator<std::variant<int, long, double, std::basic_string<char> > >()};
  {
    
    
    std::vector<std::variant<int, long, double, std::basic_string<char> >, std::allocator<std::variant<int, long, double, std::basic_string<char> > > > & __range1 = vec;
    __gnu_cxx::__normal_iterator<std::variant<int, long, double, std::basic_string<char> > *, std::vector<std::variant<int, long, double, std::basic_string<char> >, std::allocator<std::variant<int, long, double, std::basic_string<char> > > > > __begin1 = __range1.begin();
    __gnu_cxx::__normal_iterator<std::variant<int, long, double, std::basic_string<char> > *, std::vector<std::variant<int, long, double, std::basic_string<char> >, std::allocator<std::variant<int, long, double, std::basic_string<char> > > > > __end1 = __range1.end();
    for(; __gnu_cxx::operator!=(__begin1, __end1); __begin1.operator++()) {
    
    
      std::variant<int, long, double, std::basic_string<char> > & v = __begin1.operator*();
            
      class __lambda_29_20
      {
    
    
        public: 
        template<class type_parameter_0_0>
        inline /*constexpr */ auto operator()(type_parameter_0_0 && arg) const
        {
    
    
          std::cout << arg;
        }
        
        #ifdef INSIGHTS_USE_TEMPLATE
        template<>
        inline /*constexpr */ void operator()<int &>(int & arg) const
        {
    
    
          std::cout.operator<<(arg);
        }
        #endif
        
        
        #ifdef INSIGHTS_USE_TEMPLATE
        template<>
        inline /*constexpr */ void operator()<long &>(long & arg) const
        {
    
    
          std::cout.operator<<(arg);
        }
        #endif
        
        
        #ifdef INSIGHTS_USE_TEMPLATE
        template<>
        inline /*constexpr */ void operator()<double &>(double & arg) const
        {
    
    
          std::cout.operator<<(arg);
        }
        #endif
        
        
        #ifdef INSIGHTS_USE_TEMPLATE
        template<>
        inline /*constexpr */ void operator()<std::basic_string<char> &>(std::basic_string<char> & arg) const
        {
    
    
          std::operator<<(std::cout, arg);
        }
        #endif
        
        private: 
        template<class type_parameter_0_0>
        static inline /*constexpr */ auto __invoke(type_parameter_0_0 && arg)
        {
    
    
          return __lambda_29_20{
    
    }.operator()<type_parameter_0_0>(arg);
        }
        
      };
      
      std::visit(__lambda_29_20{
    
    }, v);
                  
      class __lambda_32_30
      {
    
    
        public: 
        template<class type_parameter_0_0>
        inline std::variant<int, long, double, std::basic_string<char> > operator()(type_parameter_0_0 && arg) const
        {
    
    
          return arg + arg;
        }
        
        /* First instantiated from: invoke.h:61 */
        #ifdef INSIGHTS_USE_TEMPLATE
        template<>
        inline std::variant<int, long, double, std::basic_string<char> > operator()<int &>(int & arg) const
        {
    
    
          return std::variant<int, long, double, std::basic_string<char> >(arg + arg);
        }
        #endif
        
        
        /* First instantiated from: invoke.h:61 */
        #ifdef INSIGHTS_USE_TEMPLATE
        template<>
        inline std::variant<int, long, double, std::basic_string<char> > operator()<long &>(long & arg) const
        {
    
    
          return std::variant<int, long, double, std::basic_string<char> >(arg + arg);
        }
        #endif
        
        
        /* First instantiated from: invoke.h:61 */
        #ifdef INSIGHTS_USE_TEMPLATE
        template<>
        inline std::variant<int, long, double, std::basic_string<char> > operator()<double &>(double & arg) const
        {
    
    
          return std::variant<int, long, double, std::basic_string<char> >(arg + arg);
        }
        #endif
        
        
        /* First instantiated from: invoke.h:61 */
        #ifdef INSIGHTS_USE_TEMPLATE
        template<>
        inline std::variant<int, long, double, std::basic_string<char> > operator()<std::basic_string<char> &>(std::basic_string<char> & arg) const
        {
    
    
          return std::variant<int, long, double, std::basic_string<char> >(std::operator+(arg, arg));
        }
        #endif
        
        private: 
        template<class type_parameter_0_0>
        static inline std::variant<int, long, double, std::basic_string<char> > __invoke(type_parameter_0_0 && arg)
        {
    
    
          return __lambda_32_30{
    
    }.operator()<type_parameter_0_0>(arg);
        }
        
      };
      
      std::variant<int, long, double, std::basic_string<char> > w = std::visit(__lambda_32_30{
    
    }, v);
      std::operator<<(std::cout, ". After doubling, variant holds ");
            
      class __lambda_36_20
      {
    
    
        public: 
        template<class type_parameter_0_0>
        inline /*constexpr */ auto operator()(type_parameter_0_0 && arg) const
        {
    
    
          using T = std::decay_t<decltype(arg)>;
          if constexpr(std::is_same_v<T, int>) {
    
    
            (std::operator<<(std::cout, "int with value ") << arg) << '\n';
          } else /* constexpr */ {
    
    
            if constexpr(std::is_same_v<T, long>) {
    
    
              (std::operator<<(std::cout, "long with value ") << arg) << '\n';
            } else /* constexpr */ {
    
    
              if constexpr(std::is_same_v<T, double>) {
    
    
                (std::operator<<(std::cout, "double with value ") << arg) << '\n';
              } else /* constexpr */ {
    
    
                if constexpr(std::is_same_v<T, std::basic_string<char> >) {
    
    
                  (std::operator<<(std::cout, "std::string with value ") << std::quoted(arg)) << '\n';
                } else /* constexpr */ {
    
    
                  /* PASSED: static_assert(always_false_v<T>, "non-exhaustive visitor!"); */
                  ;
                } 
                
              } 
              
            } 
            
          } 
          
        }
        
        #ifdef INSIGHTS_USE_TEMPLATE
        template<>
        inline /*constexpr */ void operator()<int &>(int & arg) const
        {
    
    
          using T = std::decay_t<int &>;
          if constexpr(true) {
    
    
            std::operator<<(std::operator<<(std::cout, "int with value ").operator<<(arg), '\n');
          } 
          
        }
        #endif
        
        
        #ifdef INSIGHTS_USE_TEMPLATE
        template<>
        inline /*constexpr */ void operator()<long &>(long & arg) const
        {
    
    
          using T = std::decay_t<long &>;
          if constexpr(false) {
    
    
          } else /* constexpr */ {
    
    
            if constexpr(true) {
    
    
              std::operator<<(std::operator<<(std::cout, "long with value ").operator<<(arg), '\n');
            } 
            
          } 
          
        }
        #endif
        
        
        #ifdef INSIGHTS_USE_TEMPLATE
        template<>
        inline /*constexpr */ void operator()<double &>(double & arg) const
        {
    
    
          using T = std::decay_t<double &>;
          if constexpr(false) {
    
    
          } else /* constexpr */ {
    
    
            if constexpr(false) {
    
    
            } else /* constexpr */ {
    
    
              if constexpr(true) {
    
    
                std::operator<<(std::operator<<(std::cout, "double with value ").operator<<(arg), '\n');
              } 
              
            } 
            
          } 
          
        }
        #endif
        
        
        #ifdef INSIGHTS_USE_TEMPLATE
        template<>
        inline /*constexpr */ void operator()<std::basic_string<char> &>(std::basic_string<char> & arg) const
        {
    
    
          using T = std::decay_t<std::basic_string<char> &>;
          if constexpr(false) {
    
    
          } else /* constexpr */ {
    
    
            if constexpr(false) {
    
    
            } else /* constexpr */ {
    
    
              if constexpr(false) {
    
    
              } else /* constexpr */ {
    
    
                if constexpr(true) {
    
    
                  std::operator<<(std::__detail::operator<<(std::operator<<(std::cout, "std::string with value "), std::quoted(arg, char('"'), char('\\'))), '\n');
                } 
                
              } 
              
            } 
            
          } 
          
        }
        #endif
        
        private: 
        template<class type_parameter_0_0>
        static inline /*constexpr */ auto __invoke(type_parameter_0_0 && arg)
        {
    
    
          return __lambda_36_20{
    
    }.operator()<type_parameter_0_0>(arg);
        }
        
      };
      
      std::visit(__lambda_36_20{
    
    }, w);
    }
    
  }
  {
    
    
    std::vector<std::variant<int, long, double, std::basic_string<char> >, std::allocator<std::variant<int, long, double, std::basic_string<char> > > > & __range1 = vec;
    __gnu_cxx::__normal_iterator<std::variant<int, long, double, std::basic_string<char> > *, std::vector<std::variant<int, long, double, std::basic_string<char> >, std::allocator<std::variant<int, long, double, std::basic_string<char> > > > > __begin1 = __range1.begin();
    __gnu_cxx::__normal_iterator<std::variant<int, long, double, std::basic_string<char> > *, std::vector<std::variant<int, long, double, std::basic_string<char> >, std::allocator<std::variant<int, long, double, std::basic_string<char> > > > > __end1 = __range1.end();
    for(; __gnu_cxx::operator!=(__begin1, __end1); __begin1.operator++()) {
    
    
      std::variant<int, long, double, std::basic_string<char> > & v = __begin1.operator*();
            
      class __lambda_55_13
      {
    
    
        public: 
        template<class type_parameter_0_0>
        inline /*constexpr */ auto operator()(type_parameter_0_0 arg) const
        {
    
    
          (std::cout << arg) << ' ';
        }
        
        #ifdef INSIGHTS_USE_TEMPLATE
        template<>
        inline /*constexpr */ void operator()<int>(int arg) const
        {
    
    
          std::operator<<(std::cout.operator<<(arg), ' ');
        }
        #endif
        
        
        #ifdef INSIGHTS_USE_TEMPLATE
        template<>
        inline /*constexpr */ void operator()<long>(long arg) const
        {
    
    
          std::operator<<(std::cout.operator<<(arg), ' ');
        }
        #endif
        
        
        #ifdef INSIGHTS_USE_TEMPLATE
        template<>
        inline /*constexpr */ auto operator()<double>(double arg) const;
        #endif
        
        
        #ifdef INSIGHTS_USE_TEMPLATE
        template<>
        inline /*constexpr */ auto operator()<std::basic_string<char> >(std::basic_string<char> arg) const;
        #endif
        
        private: 
        template<class type_parameter_0_0>
        static inline /*constexpr */ auto __invoke(type_parameter_0_0 arg)
        {
    
    
          return __lambda_55_13{
    
    }.operator()<type_parameter_0_0>(arg);
        }
        public: 
        // inline /*constexpr */ __lambda_55_13 & operator=(const __lambda_55_13 &) /* noexcept */ = delete;
        // inline /*constexpr */ __lambda_55_13(__lambda_55_13 &&) noexcept = default;
        
      };
      
      class __lambda_56_13
      {
    
    
        public: 
        inline /*constexpr */ void operator()(double arg) const
        {
    
    
          std::operator<<(std::cout.operator<<(std::fixed).operator<<(arg), ' ');
        }
        
        using retType_56_13 = void (*)(double);
        inline constexpr operator retType_56_13 () const noexcept
        {
    
    
          return __invoke;
        };
        
        private: 
        static inline /*constexpr */ void __invoke(double arg)
        {
    
    
          __lambda_56_13{
    
    }.operator()(arg);
        }
        
        public: 
        // inline /*constexpr */ __lambda_56_13 & operator=(const __lambda_56_13 &) /* noexcept */ = delete;
        // inline /*constexpr */ __lambda_56_13(__lambda_56_13 &&) noexcept = default;
        
      };
      
      
      class __lambda_57_13
      {
    
    
        public: 
        inline /*constexpr */ void operator()(const std::basic_string<char> & arg) const
        {
    
    
          std::operator<<(std::__detail::operator<<(std::cout, std::quoted(arg, char('"'), char('\\'))), ' ');
        }
        
        using retType_57_13 = void (*)(const std::string &);
        inline constexpr operator retType_57_13 () const noexcept
        {
    
    
          return __invoke;
        };
        
        private: 
        static inline /*constexpr */ void __invoke(const std::basic_string<char> & arg)
        {
    
    
          __lambda_57_13{
    
    }.operator()(arg);
        }
        
        public: 
        // inline /*constexpr */ __lambda_57_13 & operator=(const __lambda_57_13 &) /* noexcept */ = delete;
        // inline /*constexpr */ __lambda_57_13(__lambda_57_13 &&) noexcept = default;
        
      };
      
      std::visit(overloaded{
    
    __lambda_55_13(__lambda_55_13{
    
    }), __lambda_56_13(__lambda_56_13{
    
    }), __lambda_57_13(__lambda_57_13{
    
    })}, v);
    }
  }
  return 0;
}

使用变长using声明继承构造函数

除了逐个声明继承构造函数之外,现在还支持如下的方式:你可以声明一个可变参数类模板Multi,让它继承每一个参数类型的基类:

#include <iostream>
#include <string>

using namespace std;

template <typename T>
class Base {
    
    
    T value{
    
    };
   public:
    Base() {
    
    }
    Base(T v) : value{
    
    v} {
    
     cout << "value = " << value << endl; }
};

template <typename... Types>
class Multi : private Base<Types>... {
    
    
   public:
    // 继承所有构造函数:
    using Base<Types>::Base...;
};

using MultiISB = Multi<int, string, bool>;

int main() {
    
    
    MultiISB m1 = 42;
    MultiISB m2 = std::string("hello");
    MultiISB m3 = true;
}

有了所有基类构造函数的using声明,你可以继承每个类型对应的构造函数。现在,当使用不同类型声明Multi<>时:

using MultiISB = Multi<int, std::string, bool>;

你可以使用每一个相应的构造函数来声明对象:

MultiISB m1 = 42;
MultiISB m2 = std::string("hello");
MultiISB m3 = true;

根据新的语言规则,每一个初始化会调用匹配基类的相应构造函数和所有其他基类的默认构造函数。因此:

MultiISB m2 = std::string("hello");

会调用Base<int>的默认构造函数、Base<std::string>的字符串构造函数、Base<bool>的默认构造函数。
运行结果如下:

value = 42
value = hello
value = 1

预处理代码如下:

#include <iostream>
#include <string>

using namespace std;

template<typename T>
class Base
{
    
    
  T value;
  
  public: 
  inline Base()
  {
    
    
  }
  
  inline Base(T v)
  : value{
    
    v}
  {
    
    
    operator<<(operator<<(std::operator<<(std::cout, "value = "), this->value), endl);
  }
};

/* First instantiated from: insights.cpp:15 */
#ifdef INSIGHTS_USE_TEMPLATE
template<>
class Base<int>
{
    
    
  int value;
  
  public: 
  inline Base()
  : value{
    
    }
  {
    
    
  }
  
  inline Base(int v)
  : value{
    
    v}
  {
    
    
    std::operator<<(std::cout, "value = ").operator<<(this->value).operator<<(std::endl);
  }
  
};
#endif
/* First instantiated from: insights.cpp:15 */
#ifdef INSIGHTS_USE_TEMPLATE
template<>
class Base<std::basic_string<char, std::char_traits<char>, std::allocator<char> > >
{
    
    
  std::basic_string<char, std::char_traits<char>, std::allocator<char> > value;
  
  public: 
  inline Base()
  : value{
    
    std::basic_string<char, std::char_traits<char>, std::allocator<char> >{
    
    }}
  {
    
    
  }
  
  inline Base(std::basic_string<char, std::char_traits<char>, std::allocator<char> > v)
  : value{
    
    std::basic_string<char, std::char_traits<char>, std::allocator<char> >{
    
    v}}
  {
    
    
    std::operator<<(std::operator<<(std::cout, "value = "), this->value).operator<<(std::endl);
  }
  
  // inline constexpr ~Base() noexcept = default;
};
#endif
/* First instantiated from: insights.cpp:15 */
#ifdef INSIGHTS_USE_TEMPLATE
template<>
class Base<bool>
{
    
    
  bool value;
  
  public: 
  inline Base()
  : value{
    
    }
  {
    
    
  }
  
  inline Base(bool v)
  : value{
    
    v}
  {
    
    
    std::operator<<(std::cout, "value = ").operator<<(this->value).operator<<(std::endl);
  }
  
};
#endif

template<typename ... Types>
class Multi : private Base<Types>...
{
    
    
  
  public: 
  using Base<Types>::Base<type-parameter-0-0>...;
};

/* First instantiated from: insights.cpp:23 */
#ifdef INSIGHTS_USE_TEMPLATE
template<>
class Multi<int, std::basic_string<char, std::char_traits<char>, std::allocator<char> >, bool> : private Base<int>, private Base<std::basic_string<char, std::char_traits<char>, std::allocator<char> > >, private Base<bool>
{
    
    
  
  public: 
  inline Multi(int v) noexcept(false)
  : Base<int>(v)
  , Base<std::basic_string<char, std::char_traits<char>, std::allocator<char> > >()
  , Base<bool>()
  {
    
    
  }
  
  // inline constexpr ~Multi() noexcept = default;
  inline Multi(std::basic_string<char, std::char_traits<char>, std::allocator<char> > v) noexcept(false)
  : Base<int>()
  , Base<std::basic_string<char, std::char_traits<char>, std::allocator<char> > >(v)
  , Base<bool>()
  {
    
    
  }
  
  inline Multi(bool v) noexcept(false)
  : Base<int>()
  , Base<std::basic_string<char, std::char_traits<char>, std::allocator<char> > >()
  , Base<bool>(v)
  {
    
    
  }
  
};
#endif
using MultiISB = Multi<int, std::basic_string<char, std::char_traits<char>, std::allocator<char> >, bool>;

int main()
{
    
    
  Multi<int, std::basic_string<char, std::char_traits<char>, std::allocator<char> >, bool> m1 = Multi<int, std::basic_string<char, std::char_traits<char>, std::allocator<char> >, bool>(42);
  Multi<int, std::basic_string<char, std::char_traits<char>, std::allocator<char> >, bool> m2 = Multi<int, std::basic_string<char, std::char_traits<char>, std::allocator<char> >, bool>(std::basic_string<char, std::char_traits<char>, std::allocator<char> >(std::basic_string<char, std::char_traits<char>, std::allocator<char> >("hello", std::allocator<char>())));
  Multi<int, std::basic_string<char, std::char_traits<char>, std::allocator<char> >, bool> m3 = Multi<int, std::basic_string<char, std::char_traits<char>, std::allocator<char> >, bool>(true);
  return 0;
}

理论上讲,你也可以通过如下声明来支持Multi<>进行赋值操作:

template<typename... Types>
class Multi : private Base<Types>...
{
    
    
    ...
    // 派生所有赋值运算符
    using Base<Types>::operator=...;
};

猜你喜欢

转载自blog.csdn.net/MMTS_yang/article/details/130773034