将可变类型扩展到另一个

Expanding variadic types into another

我正在尝试通过执行类似的操作将一组可变类型扩展为另一种类型。

我有一个简单的特征,当 TFunction returns TReturn.

时启用
template<typename TReturn, typename TFunction>
using ReturnsType = enable_if_t<is_same<decltype(declval<TFunction>()()), 
                                TReturn>::value>;

它在所有主要编译器(VC++、GCC、CLANG)中都能完美运行。

现在我想用这个符号创建另一个:

template<typename TReturn, typename... TFunctions>
using AllReturnsType = ???

因此仅当所有传递的函数 (TFunctions...) 执行 return TReturn.

时才会启用

所以我尝试了这个实现:

template<typename TReturn, typename... TFunctions>
using AllReturnsType = void_t<ReturnsType<TReturn, TFunctions>...>;

但它在 VC++ 中失败(在 GCC 和 CLANG 中没问题)

code playground 可以在这里找到:https://godbolt.org/g/d839wp

这是 MSVC++ 中的错误吗?我怎样才能让它在所有编译器中工作?

谢谢!

编辑:我正在与 MSVC 团队成员联系,他们正在处理这件事!这是一个已确认的错误。

Is this a bug in MSVC++?

是的,我也这么认为。

how can I make it work in all compilers?

不要问我为什么,但看起来,如果你通过助手 struct for enable_if_returns 如下

template <typename T, typename F, 
          bool = std::is_same_v<T, get_return_type<F>>>
struct enIfR
{ };

template <typename T, typename F>
struct enIfR<T, F, true>
{ using type = T; };

template <typename T, typename F>
using enable_if_returns = typename enIfR<T, F>::type;

你的代码也在 MSVC 中编译。

下面是一个完整的编译(MSVC也是)的例子

#include <iostream>
#include <type_traits>

template <typename Function>
using get_return_type = decltype(std::declval<Function>()());

template <typename T, typename F,
         bool = std::is_same_v<T, get_return_type<F>>>
struct enIfR
 { };

template <typename T, typename F>
struct enIfR<T, F, true>
 { using type = T; };

template <typename T, typename F>
using enable_if_returns = typename enIfR<T, F>::type;

template<typename T, typename Function>
using enable_if_returns0 = typename std::enable_if<
   std::is_same<T, get_return_type<Function>>::value>::type;

template<typename T, typename... Functions>
using enable_if_all_returns = std::void_t<typename enIfR<T, Functions>::type...>;

int main()
{
    constexpr auto fint = []() -> int { return 1; };
    constexpr auto fstring = []() -> std::string { return "asd"; };

    (enable_if_returns<int, decltype(fint)>)0; // ok
    //(enable_if_returns<int, decltype(fstring)>)0; // fail on all (expected)
    //(enIfR<int, decltype(fstring)>::type)0; // fail on all (expected)

    (enable_if_all_returns<int, decltype(fint)>)0; // fail in MSVC (NOT expected, 'get_return_type<unknown-type>' being compiled)
    //(enable_if_all_returns<int, decltype(fint), decltype(string)>)0; // fail in all (expected)

    return 0;
}

我同意 这似乎是一个 MSVC 错误。如果我不得不猜测发生了什么,我会说这可能归结为 MSVC 仍然没有完全支持表达式 SFINAE。

似乎 they've been making steady improvements, though, and their implementation of std::result_of 被宣传要使用它。

巧合的是,你试图通过 get_return_type 实现的目标:

template<typename Function>
using get_return_type = decltype(declval<Function>()());

已经完成 std::result_of(已弃用)和 std::invoke_result

由于最新的 MSVC 似乎缺少对 std::invoke_result 的支持,看来如果我们修改您的代码以改用 std::result_of,则所有编译都很好:

template<class Function>
using get_return_type = typename std::result_of<Function()>::type;

Demo