0%

Static Polymorphism in C++ Part I

看到了Customization Point Objecttag_invoke之後,想要把
Static Polymorphism in C++這個主題總結一下,而這是第一部分

What is Static Polymorphism

基本上可以這樣定義

  • Static polymorphism with overloaded functions and templates that happens at compile time;
  • Dynamic polymorphism with interfaces that happens in run-time.
    而Static的好處在於Compile time就能知道該呼叫哪個函數,沒了Virtual table和runtime的開銷,有機會inline optimization

The simplest form - Class Template

最著名的粒子大概就是std::hash了

1
2
3
4
5
6
7
8
9
10
11
12
13
struct Foo {};

namespace std {
template <>
struct hash<Foo>
{
size_t operator()(const Foo& x) const
{
/* your code here */
}
};
}
std::unordered_map<Foo, int> map;

大概就是這個樣子

  1. 定義自己的類型
  2. 打開Library的namespace,填入需要的運重是馬
    至於優缺點嗎
    優點:
  • 只有一個參數,和一個functor operator,理解起來不困難
    缺點:
  • 需要汙染Library的namespace
  • 無法2對Library的default type做override
1
2
3
4
5
6
7
8
9
10
11
namespace std {
template <>
struct hash<double>
{
size_t operator()(const int x) const
{
/* your code here */
}
};
}
std::unordered_map<double, int> map;

這樣就直接死給你看

  • 要包含整個definition,不能只包含forward declaration

Extened Class Template - Class selection

先定義Primary template definition

1
2
3
4
5
6
namespace test {
template <typename T, typename C = void>
struct get {
int operator()() { return 42; }
};
}

FULL SPECIALIZATION

跟上面的範例差不多

1
2
3
4
5
6
namespace test {
template <>
struct get<double> {
int operator()() { return 66; }
};
}

PARTIAL SPECIALIZATION

1
2
3
4
5
6
namespace test {
template <typename T>
struct get<T, std::enable_if_t<std::is_arithmetic_v<T>>> {
int operator()() { return 11; }
};
}

SPECIALIZATION COLLISIONS

一旦我們加入了一組SPECIALIZATION

1
2
3
4
5
6
namespace test {
template <typename T>
struct get<T, std::enable_if_t<std::is_integral_v<T>>> {
int operator()() { return 33; }
};
}

就爆炸了,由於有兩組class符合條件,不知道選哪個好
比起單參數的方案,變得更複雜,更難維護
之前單參數的缺點它都有,還加上一連串的問題
增加的問題比解決的問題還多,不建議使用

Reference

C++Now 2019: JeanHeyd Meneide “The Plan for Tomorrow: Extension Points in C++ Applications”