代码之家  ›  专栏  ›  技术社区  ›  zeh

仅当类型包在C中包含特定类型时,才将方法添加到类中++

  •  1
  • zeh  · 技术社区  · 3 月前

    我正在尝试创建一个可以包含类型包的类。

    // Pack.hpp
    
    template <typename... Types>
    class Pack final {
      Pack(const std::tuple<Types...> items) : items_(std::move(items)){};
    
      std::tuple<Types...> items_;
    };
    

    但我想 Pack 公开一些基于的方法 Types 内部。例如,我想这样做:

    // Consumer.cpp
    
    Person person { ... };
    Car car { ... };
    Pack<Person, Car> personAndCarPack { { person, car } };
    Pack<Person> personPack { { person } };
    
    // Ok
    personAndCarPack.getCar();
    
    // Ok
    personAndCarPack.getPerson();
    
    // Ok
    personPack.getPerson();
    
    // Shouldn't compile - getCar() shouldn't exist!
    personPack.getCar();
    

    我想我必须或多或少地这样声明:

    // Pack.hpp
    
    template <typename... Types>
    class Pack final {
      Pack(const std::tuple<Types...> items) : items_(std::move(items)){};
    
      std::tuple<Types...> items_;
    
      Car getCar() {
        return std::get<Car>(items_);
      }
    
      Person getPerson() {
        return std::get<Person>(items_);
      }
    };
    

    但这当然暴露了中的方法 收拾 而不管类型如何。

    我得到的最接近的是:

      ...
    
      typename std::enable_if<(std::is_same_v<Types, Car> && ...), Car>::type
      getCar() {
        return std::get<Car>(items_);
      }
    
      ...
    

    但它不会编译;我明白了 'enable_if' cannot be used to disable this declaration 在中 std::is_same_v() 呼叫我可能误解了这一切是如何运作的。

    我找到了一些有一定关联的答案,但没有一个是根据我的需要结合正确因素的。

    有可能实现这个功能吗?如果是,如何?

    1 回复  |  直到 3 月前
        1
  •  2
  •   JeJo    3 月前

    有可能实现这个功能吗?如果是,如何?

    是的,这是可能的。最小的变化 á 解决方案没有 std::enable_if /SFINAE。

    // Method to get a Car from the Pack (enabled only if Car is in Types...)
    template <typename T = Car>
    constexpr auto getCar() -> decltype(std::get<Car>(items_))
    {
        return std::get<Car>(items_);
    }
    
    // Method to get a Person from the Pack (enabled only if Person is in Types...)
    template <typename T = Person>
    constexpr auto getPerson() -> decltype(std::get<Person>(items_))
    {
        return std::get<Person>(items_);
    }
    

    See live demo

    á 请记住,以上内容不会禁止在未评估的上下文中使用该函数(即。 decltype(personPack.getCar()) x = personAndCarPack.getCar(); 仍然有效)。


    或者,与 std::enable_if_t std::disjunction ,你也可能达到同样的效果。

    // Method to get a Car from the Pack (enabled only if Car is in Types...)
    template <typename T = Car>
    constexpr auto getCar()
             -> std::enable_if_t<std::disjunction<std::is_same<Types, T>...>::value, T>
    {
        static_assert(std::is_same_v<T, Car>, "T must be of type Car!");
        return std::get<T>(items_);
    }
    
    // Method to get a Person from the Pack (enabled only if Person is in Types...)
    template <typename T = Person>
    constexpr auto getPerson()
             -> std::enable_if_t<std::disjunction<std::is_same<Types, T>...>::value, T>
    {
        static_assert(std::is_same_v<T, Person>, "T must be of type Person!");
        return std::get<T>(items_);
    }
    

    See live demo


    (面向未来读者)自 然而,解决方案将更简单 requires constraints

    // Method to get a Car from the Pack (enabled only if Car is in Types...)
    constexpr auto getCar() requires (std::is_same_v<Types, Car> || ...)
    {
        return std::get<Car>(items_);
    }
    
    // Method to get a Person from the Pack (enabled only if Person is in Types...)
    constexpr auto getPerson() requires (std::is_same_v<Types, Person> || ...)
    {
        return std::get<Person>(items_);
    }
    

    See live demo