带有别名的 Variadic 模板扩展?
Variadic template expansion with aliases?
所以在我继承的代码库中,我们有一个混乱的实用程序文件,大致如下:
template <typename T, std::enable_if_t<(sizeof(T) == 1)>> int doA(const T *Data, size_t Size);
template <typename T, std::enable_if_t<(sizeof(T) == 1)>> int doB(const T *Data, size_t Size);
template <typename T> int doA(T &Input)
{ return doA<uint8_t>((uint8_t *)&Input, sizeof(T); };
template <typename T, size_t N> int doA(T(&Input)[N])
{ return doA(Input, N - 1); };
template <typename T> int doA(std::vector<T> Input)
{ return doA((uint8_t *)Input.data(), sizeof(T::value_type) * Input.size()); };
/* Repeat for doB */
所以我认为由于 doA
和 doB
非常相似,所以可以将混乱减少为:
template <bool TypeA, typename T, std::enable_if_t<(sizeof(T) == 1)>>
int do_t(const T *Data, size_t Size) { if constexpr(TypeA) ... };
template <bool TypeA, typename T> int do_t(T &Input)
{ return do_t<TypeA, uint8_t>((uint8_t *)&Input, sizeof(T); };
template <bool TypeA, typename T, size_t N> int do_t(T(&Input)[N])
{ return do_t<TypeA, T>(Input, N - 1); };
template <bool TypeA, typename T> int do_t(std::vector<T> Input)
{ return do_t<TypeA, uint8_t>((uint8_t *)Input.data(), sizeof(T::value_type) * Input.size()); };
template <typename ...Args> using doA = do_t<true, Args...>;
template <typename ...Args> using doB = do_t<false, Args...>;
// Expand to do_t<true, char, 4>(char (&Input)[4])
static_assert(doA("abc") == 123);
// Expand to do_t<false, int>(int &Input)
static_assert(doB(321) == 123);
自然地,编译器抱怨 do_t
在别名处未定义,这并没有解决。在您想要捕获所有重载的情况下,正确的方法是什么?
我想,您可以编写几个 C 风格的宏,而不是您的几个 using
声明。
但我认为 C 风格的宏是邪恶的提炼物,所以我提出了两个简单的转换函数
template <typename ... Args>
auto doA (Args && ... as)
{ return do_t<true>(std::forward<Args>(as)...); }
template <typename ... Args>
auto doB (Args && ... as)
{ return do_t<false>(std::forward<Args>(as)...); }
或者,您可以使用函子对象:
template <bool isA>
struct doT
{
template <typename T, std::enable_if_t<(sizeof(T) == 1), int> = 0>
int operator()(const T *Data, size_t Size) const
{
if constexpr (isA) { return doA_impl(Data, Size); }
else { return doB_impl(Data, Size); }
}
template <typename T>
int operator() (T &Input) const
{ return (*this)((std::uint8_t *)&Input, sizeof(T)); }
template <typename T, size_t N>
int operator() (T(&Input)[N]) const
{ return (*this)(Input, N - 1); }
template <typename T>
int operator() (std::vector<T> Input) const
{ return (*this)((std::uint8_t *)Input.data(), sizeof (T::value_type) * Input.size()); };
};
constexpr doT<true> doA{};
constexpr doT<false> doB{};
注意:ADL 不适用于与常规函数相反的仿函数对象。
所以在我继承的代码库中,我们有一个混乱的实用程序文件,大致如下:
template <typename T, std::enable_if_t<(sizeof(T) == 1)>> int doA(const T *Data, size_t Size);
template <typename T, std::enable_if_t<(sizeof(T) == 1)>> int doB(const T *Data, size_t Size);
template <typename T> int doA(T &Input)
{ return doA<uint8_t>((uint8_t *)&Input, sizeof(T); };
template <typename T, size_t N> int doA(T(&Input)[N])
{ return doA(Input, N - 1); };
template <typename T> int doA(std::vector<T> Input)
{ return doA((uint8_t *)Input.data(), sizeof(T::value_type) * Input.size()); };
/* Repeat for doB */
所以我认为由于 doA
和 doB
非常相似,所以可以将混乱减少为:
template <bool TypeA, typename T, std::enable_if_t<(sizeof(T) == 1)>>
int do_t(const T *Data, size_t Size) { if constexpr(TypeA) ... };
template <bool TypeA, typename T> int do_t(T &Input)
{ return do_t<TypeA, uint8_t>((uint8_t *)&Input, sizeof(T); };
template <bool TypeA, typename T, size_t N> int do_t(T(&Input)[N])
{ return do_t<TypeA, T>(Input, N - 1); };
template <bool TypeA, typename T> int do_t(std::vector<T> Input)
{ return do_t<TypeA, uint8_t>((uint8_t *)Input.data(), sizeof(T::value_type) * Input.size()); };
template <typename ...Args> using doA = do_t<true, Args...>;
template <typename ...Args> using doB = do_t<false, Args...>;
// Expand to do_t<true, char, 4>(char (&Input)[4])
static_assert(doA("abc") == 123);
// Expand to do_t<false, int>(int &Input)
static_assert(doB(321) == 123);
自然地,编译器抱怨 do_t
在别名处未定义,这并没有解决。在您想要捕获所有重载的情况下,正确的方法是什么?
我想,您可以编写几个 C 风格的宏,而不是您的几个 using
声明。
但我认为 C 风格的宏是邪恶的提炼物,所以我提出了两个简单的转换函数
template <typename ... Args>
auto doA (Args && ... as)
{ return do_t<true>(std::forward<Args>(as)...); }
template <typename ... Args>
auto doB (Args && ... as)
{ return do_t<false>(std::forward<Args>(as)...); }
或者,您可以使用函子对象:
template <bool isA>
struct doT
{
template <typename T, std::enable_if_t<(sizeof(T) == 1), int> = 0>
int operator()(const T *Data, size_t Size) const
{
if constexpr (isA) { return doA_impl(Data, Size); }
else { return doB_impl(Data, Size); }
}
template <typename T>
int operator() (T &Input) const
{ return (*this)((std::uint8_t *)&Input, sizeof(T)); }
template <typename T, size_t N>
int operator() (T(&Input)[N]) const
{ return (*this)(Input, N - 1); }
template <typename T>
int operator() (std::vector<T> Input) const
{ return (*this)((std::uint8_t *)Input.data(), sizeof (T::value_type) * Input.size()); };
};
constexpr doT<true> doA{};
constexpr doT<false> doB{};
注意:ADL 不适用于与常规函数相反的仿函数对象。