【问题标题】:Conditional same-arity template class code, based on template arguements?基于模板参数的条件相同模板类代码?
【发布时间】:2017-04-02 14:58:37
【问题描述】:

类似于Conditional compile-time inclusion/exclusion of code based on template argument(s)?

(顺便说一句,上述问题中的答案 2 根本无法编译)

(C++11 及以上)

我下面的类描述,希望 Outer::Inner<...> 是一个类型,以便用作模板参数等。

template<typename T>
struct Outer {
  __enable_if__(cond_1<T>()) {
    // Does not compile if T fails cond_1
    template<typename> Inner { ... }; 
  }
  __enable_if__(cond_2<T>()) {
    // Does not compile if T fails cond_2
    template<typename> Inner { ... }; 
  }
};

我只能想到某事。如下所示。

#include <type_traits>

struct BaseA { static constexpr int va = 111; };
struct BaseB { static constexpr int vb = 222; };

struct C : public BaseA {};
struct D : public BaseB {};

template<typename T>
struct Outer {
  template<typename, int selector> struct InnerImpl;

  template<typename S> struct InnerImpl<S, 1> { static constexpr int v = T::va; };
  template<typename S> struct InnerImpl<S, 2> { static constexpr int v = T::vb; };

  static constexpr int computeSelector() {
    // Could be less horrible with C++14 constexpr functions
    // std::is_base_of acts as a demo of complex compile-time conditions
    return std::is_base_of<BaseA, T>::value + std::is_base_of<BaseB, T>::value * 2;
  } // **1

  template<typename S> using Inner = InnerImpl<S, computeSelector()>;
};

问题是这种方式根本无法扩展。

Outer 依赖于所有可能的 T,这很容易导致循环头依赖。

有没有Outer不依赖于T的解决方案?

【问题讨论】:

  • 您是否只需要Inner&lt;U&gt; 的两个潜在实现?您希望它以何种方式扩展?
  • 两种以上的潜在实现。在实际场景中,BaseA、BaseB 和 Outer 位于不同的标头(以及逻辑上不同的模块)中。因此,我想消除 Outer 对每个相关类型的依赖。
  • 我想要的:如果在翻译单元中没有使用 Outer 类型,则翻译单元不必包含 BaseA、BaseB 等的所有相关标头。

标签: c++ c++11 templates


【解决方案1】:

不确定是否理解您的问题,但我已尝试简化您的示例。

以下解决方案有什么问题?

#include <iostream>
#include <type_traits>

struct BaseA { static constexpr int va = 111; };
struct BaseB { static constexpr int vb = 222; };

struct C : public BaseA {};
struct D : public BaseB {};

template<typename T>
struct Outer
 {
   template <typename S, bool B = true>
   struct InnerI;

   template <typename S>
   struct InnerI<S, std::is_base_of<BaseA, T>::value>
    { static constexpr int v { T::va }; };

   template <typename S>
   struct InnerI<S, std::is_base_of<BaseB, T>::value>
    { static constexpr int v { T::vb }; };

   template <typename S>
   using Inner = InnerI<S>;
 };


int main()
 {
   std::cout << Outer<C>::Inner<int>::v    << std::endl;    // print 111
   std::cout << Outer<D>::Inner<long>::v   << std::endl;    // print 222
   // std::cout << Outer<int>::Inner<char>::v << std::endl; // compilation error
 }

【讨论】:

  • 我想要的:如果类型 Outer 未在翻译单元中使用,则翻译单元不必包含 BaseA、BaseB 等的所有相关标头。 std::is_base_of 需要定义参数类型, 这将引入 header 依赖。
猜你喜欢
  • 2023-03-12
  • 1970-01-01
  • 2011-08-05
  • 1970-01-01
  • 2018-07-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多