如何使用 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"
}

Demo