【问题标题】:Template class with conditional typenames具有条件类型名的模板类
【发布时间】:2020-10-27 09:56:41
【问题描述】:

我想要一个模板类(例如 float/double 类型),但我使用的是 Nvidia CUDAOptiX 并且有多种其他类型(例如float2double2float3、...)取决于所选模板类型。

类似这样的:

#include <optixu/optixu_vector_types.h>
#include <type_traits>

template <class T>
class MyClass 
{
   MyClass()
   {
      if (std::is_same<T, float>::value) 
      {
         typedef optix::float2 T2;
      }
      else if (std::is_same<T, double>::value)
      {
         typedef optix::double2 T2;
      }

      T2 my_T2_variable;
   }

   void SomeFunction() 
   { 
      T2 another_T2_variable; 
   };
};

我现在的解决方案是有多个模板参数MyClass&lt;T,T2,T3&gt; my_object;,但这似乎有太多的开销和混乱。有没有一种方法可以使用上面所需的单个模板参数来实现相同的效果?

【问题讨论】:

标签: c++ class c++11 templates class-template


【解决方案1】:

通常,您会通过创建其特化定义附加类型的特征类型来做到这一点。例如:

// Base template is undefined.
template <typename T>
struct optix_traits;

template <>
struct optix_traits<float> {
    using dim2 = optix::float2;
    // etc
};

template <>
struct optix_traits<double> {
    using dim2 = optix::double2;
    // etc
};

然后,如果需要,您可以从这些类型中将其别名为您的类型中的名称:

template <typename T>
class MyClass {
public:
    using T2 = typename optix_traits<T>::dim2;
};

【讨论】:

  • 那行得通。谢谢。稍微注意一下:我刚刚注意到我有返回 T2/T3 的私有成员函数,它会引发关于未知(返回)类型 T2 的错误?例如。 T2 MyClass&lt;T&gt;::Foo(){return my_T2_variable;} 可以通过某种方式解决吗?还是我应该发布一个新问题?
  • @SemtexB 类外成员函数定义在它知道成员属于什么类型之前不是“范围内”。当它在那里看到T2 时,它不知道T2 是什么,因为它还不知道该方法在MyClass&lt;T&gt; 中。拼写出来:template &lt;typename T&gt; typename MyClass&lt;T&gt;::T2 MyClass&lt;T&gt;::Foo() { ... } 从 C++11 开始,您还可以使用 auto 移动返回类型,如下所示:template &lt;typename T&gt; auto MyClass&lt;T&gt;::Foo() -&gt; T2 { ... }。由于在这种情况下返回类型出现在MyClass&lt;T&gt;:: 之后,它知道在MyClass&lt;T&gt; 中查找它。
  • 完美,成功了。感谢您的快速回复。我尝试了template &lt;typename T&gt; MyClass::T2 MyClass&lt;T&gt;::Foo() { ... },但忘记了typename 关键字和模板参数...doh!
  • 总结:虽然所有模板都是元函数,但类型特征是我们想要通过枚举所有可能性来或多或少地定义它们时使用的特定习惯用法,以及函数的输出在哪里(s) 是关于类型的一堆“事实”(或者您可以将它们称为类型的属性或 traits)。因此,从类型列表到其他类型列表的简单映射几乎一种类型特征,无论您是否认为将其命名。
【解决方案2】:

您可以使用std::conditional,来自&lt;type_traits&gt;

如果您希望T2T == float 时为optix::float2,否则为optix::double2,请使用std::conditional。这在 之后可用,并将在编译时解析T2 类型。

#include <type_traits>  // std::conditional, std::is_same

template <class T>
class MyClass
{
    using T2 = typename std::conditional<std::is_same<T, float>::value,
                                          optix::float2, optix::double2>::type;
    T2 my_T2_variable;

    // ... other code
};

(See demo)


正如@HikmatFarhat 所指出的,std::conditional 不会捕捉到用户的错误。 它只检查第一个条件,对于false 的情况,给出optix::double2 类型。

另一个选项是一系列 SFINAE ed 函数,以及 decltypeT2 的函数如下:

#include <type_traits>  // std::is_same, std::enable_if

template <class T> // uses if T == float and return `optix::float2`
auto typeReturn() -> typename std::enable_if<std::is_same<float, T>::value, optix::float2>::type { return {}; }

template <class T> // uses if T == double and return `optix::double2`
auto typeReturn() -> typename std::enable_if<std::is_same<double, T>::value, optix::double2>::type { return {}; }

template <class T>
class MyClass
{
    using T2 = decltype(typeReturn<T>()); // chooses the right function!

    T2 my_T2_variable;

    // ... other codes
};

(See demo)

【讨论】:

  • 是的,但如果他犯了错误,std::conditional 将无法捕捉到它。例如用 std::string 调用它,它默认为 optix::double2。而 type_trait 解决方案会报错。
  • @HikmatFarhat 你是对的。添加了另一个选项,类似于 type_trait 解决方案,应该涵盖该问题。
【解决方案3】:

使用模板特化实现一个元函数,将标准 C++ 类型映射到具有所需“等级”的 OptiX 类型:

template <typename T, std::size_t N> struct optix_type;

template <> struct optix_type<float, 2> { using type = optix::float2; };
template <> struct optix_type<float, 3> { using type = optix::float3; };
template <> struct optix_type<double, 2> { using type = optix::double2; };
// ...

template <typename T, std::size_t N>
using optix_type_t = typename optix_type<T, N>::type;

然后您可以在您的课程中使用它来轻松获得正确的类型:

template <class T>
class MyClass {
  using T2 = optix_type_t<T, 2>;
  MyClass() {
    T2 my_T2_variable;
    optix_type_t<T, 3> my_T3_variable;
  }
  void SomeFunction() { T2 another_T2_variable; };
};

【讨论】:

    猜你喜欢
    • 2021-12-08
    • 2023-01-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-03-28
    • 1970-01-01
    • 2021-09-24
    相关资源
    最近更新 更多