【问题标题】:C++ Type, Function, And Value Aliasing For Potentially Undefined Types潜在未定义类型的 C++ 类型、函数和值别名
【发布时间】:2021-11-17 06:24:31
【问题描述】:

假设我有两个库,我们随意称它们为“CUDA”和“HIP”。这两个库恰好有非常相似的接口,我想将这些接口包装到一个模板化类中,其中模板参数定义调用哪个库。我目前的实现是(以简略形式):

#define ALIAS_FUNCTION(Alias_,Original_)              \
  template <typename... Args> Alias_(Args&&... args)  \
  -> decltype(Original_(std::forward<Args>(args)...)) \
  { return Original_(std::forward<Args>(args)...); }

enum class Selector {CUDA,HIP};

template <Selector T> struct Interface;

#if (havecuda)
#  include <cuda_headers.h>
template <>
struct Interface<Selector::CUDA>
{
  using error_type = cudaError_t;
  static const auto success = cudaSuccess;

  ALIAS_FUNCTION(static constexpr getLastError,cudaGetLastError);
};
#endif

#if (havehip)
#  include <hip_headers.h>
template <>
struct Interface<Selector::HIP>
{
  using error_type = hipError_t;
  static const auto success = hipSuccess;

  ALIAS_FUNCTION(static constexpr getLastError,hipGetLastError);
};
#endif

虽然这有效,但维护起来非常痛苦,因为我需要复制每个别名,并确保相当一部分样板文件是正确的。更不用说宏了。理想情况下,我想要的是将所有内容保持在一个定义中,例如:

template <Selector T>
struct Interface
{
  using error_type = std::conditional<T==Selector::CUDA,cudaError_t,hipError_t>;
  // do something similar to solve the function and variable aliasing
};

但是唉std::conditional 要求至少声明这两种类型。这里有更聪明的解决方案吗?理想情况下,它也应该是 C++11。

编辑:(只是为了更明显地回答 cmets 的问题) Interface 类的想法是,还有其他派生自它的类(假设 havecudahavehip 之一为真)以便获得对这些类型的访问:

template <Selector T>
class DoWork : Interface<T>
{
  using typename Interface<T>::error_type;
  using Interface<T>::success;
  using Interface<T>::getLastError;

  void work()
  {
    error_type err;
    if (getLastError() != success) {
      // something else
    }
  }
};

// instantiate the work classes if available
#if havecuda
template class DoWork<Selector::CUDA>;
#endif
#if havehip
template class DoWork<Selector::HIP>;
#endif

【问题讨论】:

  • std::conditional 真的需要定义类型吗?声明可能就足够了。
  • 前向声明就足够了,但我还必须处理另一个既没有定义也没有声明的情况。例如。 havecuda = 1havehip = 0。在这种情况下,std::conditional 崩溃了……
  • 编译时havecudahavehip 都可以吗?
  • 是的,因此我使用模板而不是纯宏。这个想法是第三个类DoWork&lt;Selector T&gt; : Interface&lt;T&gt;继承了using Interface&lt;T&gt;::success的定义。

标签: c++ c++11 cuda sfinae


【解决方案1】:

如何形成不同实现的重载集?此解决方案甚至不需要类模板(尽管如果您不介意额外的样板,您仍然可以将其重新添加)。

#define TAGGED_ALIAS_FUNCTION(Tag_, Alias_,Original_)            \
  template <typename... Args> auto Alias_(Tag_, Args&&... args)  \
  -> decltype(Original_(std::forward<Args>(args)...))            \
  { return Original_(std::forward<Args>(args)...);}

namespace Selector {
    struct CUDA {};
    struct HIP {};
}

#if (havecuda)
#include <cuda_headers.h>
  TAGGED_ALIAS_FUNCTION(Selector::CUDA, static constexpr getLastError,cudaGetLastError);
#endif

#if (havehip)
  TAGGED_ALIAS_FUNCTION(Selector::HIP, static constexpr getLastError,hipGetLastError);
#endif

template<typename Selector_T>
void myFunction()
{
   auto const last_error = getLastError(Selector_T{});
} 

【讨论】:

  • 嗯,我看到这种方法的问题是很难阻止人们在同一组调用中混合两个库。至少对于类,您可以通过提供它们本身的类来强制使用哪些类型/函数。但我怀疑这些缺点主要是因为我想要的东西在 c++ 中还不可能实现...... :(
猜你喜欢
  • 1970-01-01
  • 2012-09-14
  • 2012-07-28
  • 2012-03-04
  • 1970-01-01
  • 1970-01-01
  • 2019-06-21
  • 1970-01-01
  • 2012-02-20
相关资源
最近更新 更多