将可变类型扩展到另一个
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;
我正在尝试通过执行类似的操作将一组可变类型扩展为另一种类型。
我有一个简单的特征,当 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;
}
我同意
似乎 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;