如何使用 class 模板专业化避免代码重复
How to avoid code duplicates with class template specializations
我想避免以下代码中的重复项。
#include <iostream>
struct Bar{};
template <class... Args>
struct FooClass;
template <class... Args>
inline void foo(Args&&... args) {
FooClass<Args...>::impl(std::forward<Args>(args)...);
}
// Duplicate 1.
// Const ref version
template <>
struct FooClass<Bar const&> {
inline static void impl(const Bar& b) {
std::cout << "dup1" << std::endl;
}
};
// Duplicate 2.
// Copy version
template <>
struct FooClass<Bar> {
inline static void impl(const Bar& b) {
std::cout << "dup2" << std::endl;
}
};
// Duplicate 3.
// Non-const ref version
template <>
struct FooClass<Bar&> {
inline static void impl(const Bar& b) {
std::cout << "dup3" << std::endl;
}
};
int main()
{
const Bar b2;
foo(b2);
foo(Bar{});
Bar b;
foo(b);
}
我很确定这可以通过 enable_if 和通用引用以某种方式实现,但我无法弄清楚。
顺便说一句,这个程序输出:
dup1
dup2
dup3
如果三个专业化中的任何一个被注释掉,它都不会编译。
因为你完美地将你的参数转发给 impl
,据我所知,你将需要所有重复项,因为编译器必须与专业化的类型完全匹配。
一个简单的解决方法是复制所有内容:
#include <iostream>
struct Bar{};
template <class... Args>
struct FooClass;
template <class... Args>
inline void foo(Args... args) {
FooClass<Args...>::impl(args...);
}
// Duplicate 1.
// Const ref version
template <>
struct FooClass<Bar> {
inline static void impl(const Bar& b) {
std::cout << "dup1" << std::endl;
}
};
int main()
{
const Bar b2;
foo(b2);
foo(Bar{});
Bar b;
foo(b);
}
这在 Clang 12.0.0 中编译得很好。
为什么不直接从模板参数中删除 const
和 &
?
template<class... Args>
void foo(Args&&... args) {
FooClass<std::decay_t<Args>...>::impl(std::forward<Args>(args)...);
// ^^^^^^^^^^^^
}
template<>
struct FooClass<Bar> {
static void impl(const Bar&) {
std::cout << "bar" << std::endl;
}
};
int main() {
const Bar b2;
foo(b2); // prints "bar"
foo(Bar{}); // prints "bar"
Bar b;
foo(b); // prints "bar"
}
我想避免以下代码中的重复项。
#include <iostream>
struct Bar{};
template <class... Args>
struct FooClass;
template <class... Args>
inline void foo(Args&&... args) {
FooClass<Args...>::impl(std::forward<Args>(args)...);
}
// Duplicate 1.
// Const ref version
template <>
struct FooClass<Bar const&> {
inline static void impl(const Bar& b) {
std::cout << "dup1" << std::endl;
}
};
// Duplicate 2.
// Copy version
template <>
struct FooClass<Bar> {
inline static void impl(const Bar& b) {
std::cout << "dup2" << std::endl;
}
};
// Duplicate 3.
// Non-const ref version
template <>
struct FooClass<Bar&> {
inline static void impl(const Bar& b) {
std::cout << "dup3" << std::endl;
}
};
int main()
{
const Bar b2;
foo(b2);
foo(Bar{});
Bar b;
foo(b);
}
我很确定这可以通过 enable_if 和通用引用以某种方式实现,但我无法弄清楚。
顺便说一句,这个程序输出:
dup1
dup2
dup3
如果三个专业化中的任何一个被注释掉,它都不会编译。
因为你完美地将你的参数转发给 impl
,据我所知,你将需要所有重复项,因为编译器必须与专业化的类型完全匹配。
一个简单的解决方法是复制所有内容:
#include <iostream>
struct Bar{};
template <class... Args>
struct FooClass;
template <class... Args>
inline void foo(Args... args) {
FooClass<Args...>::impl(args...);
}
// Duplicate 1.
// Const ref version
template <>
struct FooClass<Bar> {
inline static void impl(const Bar& b) {
std::cout << "dup1" << std::endl;
}
};
int main()
{
const Bar b2;
foo(b2);
foo(Bar{});
Bar b;
foo(b);
}
这在 Clang 12.0.0 中编译得很好。
为什么不直接从模板参数中删除 const
和 &
?
template<class... Args>
void foo(Args&&... args) {
FooClass<std::decay_t<Args>...>::impl(std::forward<Args>(args)...);
// ^^^^^^^^^^^^
}
template<>
struct FooClass<Bar> {
static void impl(const Bar&) {
std::cout << "bar" << std::endl;
}
};
int main() {
const Bar b2;
foo(b2); // prints "bar"
foo(Bar{}); // prints "bar"
Bar b;
foo(b); // prints "bar"
}