在函数模板中,如何根据另一个参数确定一个参数的类型
In function template, how to determine type of one argument based on another
我想实现一个带有两个参数的函数模板,一个 T* 和一个 T,但是第二个参数的类型由第一个参数决定。这是一个最小的非工作示例:
#include <cstddef>
#include <cstring>
#include <cstdint>
#include <type_traits>
#include <vector>
template<typename T> void
patch(T *dst, T src)
{
static_assert(std::is_standard_layout_v<T>);
std::byte *p = reinterpret_cast<std::byte *>(&src);
std::vector newval(p, p + sizeof(src));
// In the real code, memcpy happens later if a transaciton commits
std::memcpy(dst, newval.data(), newval.size());
}
int
main()
{
std::uint16_t u16;
patch(&u16, 0); // Fails to compile because 0 is int, not uint16_t
}
不幸的是,此代码无法编译,因为无法在 patch(&u16, 0)
中推断出要修补的类型 T,因为 0 是 int 而不是 std::uint16_t
。显然我可以转换 0 或调用 patch<uint16_t>(...)
,但在理想情况下我不必这样做。
另一方面,如果第二个参数涉及某种非平凡类型的计算,我可以解决这个问题。例如,如果我将函数声明为:
,代码将编译
template<typename T> void
patch(T *dst, std::decay_t<T> src) {/*...*/}
当我最初问这个问题时,我实施了以下并认为它不起作用。但是,我一定是犯了一个错误,因为正如所选答案所指出的那样,它确实有效:
template<typename T> struct sametype {
using type = T;
};
template<typename T> using sametype_t = typename sametype<T>::type;
template<typename T> void
patch(T *dst, sametype_t<T> src) {/*...*/}
我的问题是可以应用于模板函数参数以强制其类型由同一函数的不同参数的类型推断的最小转换是什么?
这是可以接受的解决方案吗?
template<typename T, typename U> void
patch(T *dst, U src)
{
T s = src;
static_assert(std::is_standard_layout_v<T>);
std::byte *p = reinterpret_cast<std::byte *>(&s);
std::vector newval(p, p + sizeof(T));
// In the real code, memcpy happens later if a transaciton commits
std::memcpy(dst, newval.data(), newval.size());
}
这正是 std::type_identity_t<T>
旨在解决的场景。此转换创建了所谓的 非推导上下文 ,您已为类型 T
的第二个参数请求了它。不幸的是,这种类型特征直到 C++20 标准才被引入。
您可以继续use the one you've implemented (which by the way, yes it does compile at least according to godbolt), or if you're using boost, there is a boost::type_identity_t<T>
可用。
虽然要直接回答您的问题,但我相信 C++17 中最最小 必要的转换之一是 this:
template<typename T> void
patch(T *dst, std::enable_if_t<true, T> src)
我想实现一个带有两个参数的函数模板,一个 T* 和一个 T,但是第二个参数的类型由第一个参数决定。这是一个最小的非工作示例:
#include <cstddef>
#include <cstring>
#include <cstdint>
#include <type_traits>
#include <vector>
template<typename T> void
patch(T *dst, T src)
{
static_assert(std::is_standard_layout_v<T>);
std::byte *p = reinterpret_cast<std::byte *>(&src);
std::vector newval(p, p + sizeof(src));
// In the real code, memcpy happens later if a transaciton commits
std::memcpy(dst, newval.data(), newval.size());
}
int
main()
{
std::uint16_t u16;
patch(&u16, 0); // Fails to compile because 0 is int, not uint16_t
}
不幸的是,此代码无法编译,因为无法在 patch(&u16, 0)
中推断出要修补的类型 T,因为 0 是 int 而不是 std::uint16_t
。显然我可以转换 0 或调用 patch<uint16_t>(...)
,但在理想情况下我不必这样做。
另一方面,如果第二个参数涉及某种非平凡类型的计算,我可以解决这个问题。例如,如果我将函数声明为:
,代码将编译template<typename T> void
patch(T *dst, std::decay_t<T> src) {/*...*/}
当我最初问这个问题时,我实施了以下并认为它不起作用。但是,我一定是犯了一个错误,因为正如所选答案所指出的那样,它确实有效:
template<typename T> struct sametype {
using type = T;
};
template<typename T> using sametype_t = typename sametype<T>::type;
template<typename T> void
patch(T *dst, sametype_t<T> src) {/*...*/}
我的问题是可以应用于模板函数参数以强制其类型由同一函数的不同参数的类型推断的最小转换是什么?
这是可以接受的解决方案吗?
template<typename T, typename U> void
patch(T *dst, U src)
{
T s = src;
static_assert(std::is_standard_layout_v<T>);
std::byte *p = reinterpret_cast<std::byte *>(&s);
std::vector newval(p, p + sizeof(T));
// In the real code, memcpy happens later if a transaciton commits
std::memcpy(dst, newval.data(), newval.size());
}
这正是 std::type_identity_t<T>
旨在解决的场景。此转换创建了所谓的 非推导上下文 ,您已为类型 T
的第二个参数请求了它。不幸的是,这种类型特征直到 C++20 标准才被引入。
您可以继续use the one you've implemented (which by the way, yes it does compile at least according to godbolt), or if you're using boost, there is a boost::type_identity_t<T>
可用。
虽然要直接回答您的问题,但我相信 C++17 中最最小 必要的转换之一是 this:
template<typename T> void
patch(T *dst, std::enable_if_t<true, T> src)