有条件地启用非模板函数 c++

Conditionally enable non-template function c++

本文关键字:函数 c++ 启用 有条件      更新时间:2023-10-16

>Background

我正在使用 MPI 进行高性能计算的C++项目。我有一个具有几个不同重载的函数,我用它来将不同类型的字符串转换为字符串:

void append(std::string& s, int value);
void append(std::string& s, void* value);
void append(std::string& s, MPI_Request request); 

当我使用Open MPI时,这工作正常。在OpenMPI中,MPI_Requestompi_request_t*的别名,因此每个重载都有不同的签名。

但是,最近,我尝试使用MPICH编译代码。在 MPICH 中,MPI_Requestint的别名,结果是上面的代码编译失败,因为append被定义为int两次:

/home/me/NimbleSM/src/mpi-buckets/src/mpi_err.hpp: At global scope:
/home/me/NimbleSM/src/mpi-buckets/src/mpi_err.hpp:28:6: error: redefinition of ‘void append(std::__cxx11::string&, int)’
void append(std::string& s, int i) { s.append(std::to_string(i)); }
^~~
/home/me/NimbleSM/src/mpi-buckets/src/mpi_err.hpp:17:6: note: ‘void append(std::__cxx11::string&, MPI_Request)’ previously defined here
void append(std::string& s, MPI_Request request)

问题

我应该如何编写append(std::string&, MPI_Request),以便编译器在MPI_Request定义为int时忽略它,但在MPI_Request是库类型时识别它?

尝试的解决方案:enable_if失败

我尝试编写一个基于std::enable_if的解决方案,其中仅当MPI_Requestint的类型不同时才启用该功能。

auto append(std::string& s, MPI_Request request)
-> typename std::enable_if<!std::is_same<MPI_Request, int>::value, void>::type
{ 
str(s, (void*)request); 
}

这失败了,因为当MPI_Requestint相同时,该语句始终为 false,并且由于它不依赖于任何模板参数,编译器断然拒绝编译它。

我如何解决这个问题,并使append取决于MPI_Requestint不同?

这很不幸。底线是enable_if只能在需要 T 模板的 SFINAE 上下文中使用。为了迭代您的想法,我们可以在返回类型中指定我们的要求,以便模板仅与MPI_Request匹配,并且仅当MPI_Request类型不是int

#include <string>
#include <type_traits>
using MPI_Request = int;// Or something else
template<typename T>
using T_is_MPI_and_not_also_int = std::conjunction<std::is_same<T,MPI_Request>, std::negation<std::is_same<MPI_Request,int>>>;
template<typename T>
std::enable_if_t<T_is_MPI_and_not_also_int<T>::value,void> 
append(std::string& s, T request);

完整的示例,您甚至可以看到哪个cout行内联到 main 中。

您可以使用默认模板参数使其成为函数模板,这允许 SFINAE 工作:

void append(std::string& s, int value);
void append(std::string& s, void* value);
template <typename MPI_Request_ = MPI_Request,
typename std::enable_if<
!std::is_same<MPI_Request_, int>::value
&& std::is_same<MPI_Request_, MPI_Request>::value
, int>::type = 0>
void append(std::string& s, MPI_Request_ request)
{ 
str(s, (void*)request);
// Or, if you want the implementation in the source file,
// call another function like: append_mpi_request(s, request);
}

演示

这是一个低技术解决方案。使用预处理器宏。

void append(std::string& s, int value);
void append(std::string& s, void* value);
#ifdef MPI_REQUEST_IS_INT
// No need to declare append() for MPI_Request
#else
void append(std::string& s, MPI_Request request); 
#endif

在.cpp文件中使用相同的策略。