问题
I'd like to avoid the duplicates in the code below.
#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);
}
I'm pretty sure this is possible using enable_if and universal references somehow, but I could not figure it out.
Btw., this program outputs:
dup1
dup2
dup3
and it won't compile if any of the three specializations are commented out.
回答1:
Why not just strip off const
and &
from the template argument?
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"
}
Demo
回答2:
Since you're perfectly forwarding your arguments to impl
, as far as I know, you're going to need to have all the duplicates, since the compiler has to exactly match the type for specializations.
A simple fix would be to just copy everything:
#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);
}
This compiles fine in Clang 12.0.0.
来源:https://stackoverflow.com/questions/65502524/how-to-avoid-code-duplicates-with-class-template-specializations