std::conditional - 即使在测试 'void' 时,参数类型“void”也是无效的

std::conditional - Invalid parameter type ‘void’ even when testing for 'void'

以下在 Visual Studio 上编译:

template<typename ArgType, typename ReturnType>
struct Test
{
    using FunctionPointerType = std::conditional_t<
        std::is_same_v<ArgType, void>
        , ReturnType(*)()
        , ReturnType(*)(ArgType)
    >;
    FunctionPointerType Func;
};

int main()
{
    Test<void, char> tt;
}

但不能在 Linux g++ 上编译。我得到的错误是

error : invalid parameter type ‘void’

我知道我不能在模板中使用 void,这就是我使用 std::conditional_tstd::is_same_v.

的原因

我看不出哪里不对,有人可以告诉我吗?

不是您问题的真正答案(为什么我的代码不起作用),但这有效:

template<typename ArgType, typename ReturnType>
struct Test
{
  using FunctionPointerType = ReturnType(*)(ArgType);
  FunctionPointerType Func;
};

template<typename ReturnType>
struct Test<void, ReturnType>
{
  using FunctionPointerType = ReturnType(*)();
  FunctionPointerType Func;
};
template<typename ArgType, typename ReturnType>
struct Test
{
  using FunctionPointerType = std::conditional_t<std::is_same_v<ArgType, void>, ReturnType(*)(), ReturnType(*)(ArgType)>;
  FunctionPointerType Func;
};

conditional_t 接受 3 个参数。一种bool和2种。

正确的类型,当 ArgTypevoid 时,是 ReturnType(*)(void) -- 不是合法类型。

错误立即发生。

MSVC 有个坏习惯,就是把模板当作宏来处理。

像这样:

template<class...Args>
struct Apply {
  template<template<class...>class Z>
  using To = Z<Args...>;
};

template<class R, class...Args>
using FunctionPtr = R(*)(Args...);

template<typename ArgType, typename ReturnType>
struct Test
{
  using FunctionPointerType =
    std::conditional_t<
      std::is_same_v<ArgType, void>,
      Apply<ReturnType>,
      Apply<ReturnType, ArgType>
    >::template To<FunctionPtr>;
  FunctionPointerType Func;
};

构建 2 包应用程序,然后将一个应用到 FunctionPtr,具体取决于选择的是哪一个。

在这里,我避免在条件分支发生之前形成 X(void) 类型。

std::conditional_t<B, T, F> 中,truefalse 专业化都应该具有有效类型 T 以及 F。在您的情况下,由于 F 推断为无效的 char(*)(void) 类型,因此无法在此处使用 std::conditional

我会建议一个辅助特征 function_ptr_t 作为替代

#include <type_traits>

template<typename RetType, typename... Args> struct function_ptr final {
    using type = RetType(*)(Args...);
};

template <typename RetType> struct function_ptr<RetType, void> final {
    using type = RetType(*)();
};
// alias helper
template<typename RetType, typename... Args>
using function_ptr_t = typename function_ptr<RetType, Args...>::type;


template<typename RetType, typename... Args>
struct Test
{
     function_ptr_t<RetType, Args...> Func;
};

See a demo


请注意,我已经交换了 class 模板 Test 中的模板参数,并将第二个模板参数设为可变参数,这样 Test<char> 将导致char(*)().

类型的成员函数指针

这意味着以下将起作用:

Test<char> tt1;
static_assert(std::is_same_v<char(*)(), decltype(tt1.Func)>, " are not same!");

Test<char, void> tt2;
static_assert(std::is_same_v<char(*)(), decltype(tt2.Func)>, " are not same!");

Test<void, double> tt3;
static_assert(std::is_same_v<void(*)(double), decltype(tt3.Func)>, " are not same!");

如果这不是您想要的,请将可变参数模板参数替换为普通参数。