How to avoid code duplicates with class template specializations

依然范特西╮ 提交于 2021-01-03 15:48:59

问题


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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!