Guia Completo do C++17 - Estendido usando declaração de recursos de modelo


using Uma lista de nomes separados por vírgula pode ser suportada após a expansão declarativa e esse recurso também pode ser usado para pacotes de parâmetros.
Por exemplo, agora você pode escrever:

#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();
}

O resultado da operação é o seguinte:

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

O código de pré-processamento é o seguinte:

#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;
}

Antes C++17, você precisa usar 3 usingdeclarações para declarar separadamente.

Use declarações using de comprimento variável

As declarações separadas por vírgula usingpermitem derivar a mesma operação de um número variável de todas as classes base no código genérico . Uma aplicação legal
dessa técnica é criar uma coleção sobrecarregada. Ao definir:lambda

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

Você pode sobrecarregar os dois assim lambda:

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

Aqui, criamos um overloadobjeto de tipo e fornecemos guias de dedução para deduzir o tipo da classe base lambdaa partir overloaddo tipo. A inicialização agregada também é usada para chamar lambdao construtor de cópia de cada tipo de fechamento gerado para inicializar o subobjeto da classe base. A declaração no exemplo acima usingtorna overloado tipo acessível ao operador de chamada de função em todas as subclasses ao mesmo tempo. Sem essa usingdeclaração, duas classes base produziriam sobrecargas da mesma função de membro operator(), o que levaria à ambigüidade. Finalmente, se você passar um argumento de string, a primeira sobrecarga será invocada, outros tipos (para os quais o operador é *=válido) invocarão a segunda sobrecarga:

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

resultado da operação:

i: 84
s: hihi

O código de pré-processamento é o seguinte:

#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;
}

Outra aplicação dessa técnica são std::variantos acessadores, conforme a seguir:

#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);
    }
}

O resultado da operação é o seguinte:

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

O código de pré-processamento é o seguinte:

#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;
}

Use comprimento variável usando declarações para herdar construtores

Além de declarar construtores herdados um por um, os seguintes métodos agora são suportados: você pode declarar um modelo de classe de parâmetro variável Multie deixá-lo herdar a classe base de cada tipo de parâmetro:

#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;
}

Com todos os construtores de classe base usingdeclarados, você pode herdar os construtores correspondentes para cada tipo. Agora, quando declarado com um tipo diferente Multi<>:

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

Você pode declarar objetos usando cada um dos construtores correspondentes:

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

De acordo com as novas regras de linguagem, cada inicialização chama o construtor correspondente da classe base correspondente e o construtor padrão de todas as outras classes base. portanto:

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

Base<int>O construtor padrão, Base<std::string>o construtor de string e Base<bool>o construtor padrão serão chamados .
O resultado da operação é o seguinte:

value = 42
value = hello
value = 1

O código de pré-processamento é o seguinte:

#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<>Em teoria, você também pode dar suporte a atribuições com a seguinte declaração :

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

Acho que você gosta

Origin blog.csdn.net/MMTS_yang/article/details/130773034
Recomendado
Clasificación