Skip to the content.

非类型模板参数(Non-type Template Parameter)

#include <bitset>
#include <cassert>

namespace jc {

template <bool IsSet = true, std::size_t N>
std::size_t find_next(const std::bitset<N>& b, std::size_t cur) {
  for (std::size_t i = cur + 1; i < N; ++i) {
    if (!(b.test(i) ^ IsSet)) {
      return i;
    }
  }
  return N;
}

template <bool IsSet = true, std::size_t N>
std::size_t find_prev(const std::bitset<N>& b, std::size_t cur) {
  if (cur > N) {
    cur = N;
  }
  for (int i = static_cast<int>(cur) - 1; i >= 0; --i) {
    if (!(b.test(i) ^ IsSet)) {
      return i;
    }
  }
  return N;
}

template <bool IsSet = true, std::size_t N>
std::size_t circular_find_next(const std::bitset<N>& b, std::size_t cur) {
  if (cur > N) {
    cur = N;
  }
  std::size_t res = find_next<IsSet>(b, cur);
  if (res != N) {
    return res;
  }
  for (std::size_t i = 0; i < cur; ++i) {
    if (!(b.test(i) ^ IsSet)) {
      return i;
    }
  }
  return N;
}

template <bool IsSet = true, std::size_t N>
std::size_t circular_find_prev(const std::bitset<N>& b, std::size_t cur) {
  if constexpr (N == 0) {
    return N;
  }
  std::size_t res = find_prev<IsSet>(b, cur);
  if (res != N) {
    return res;
  }
  for (std::size_t i = N - 1; i > cur; --i) {
    if (!(b.test(i) ^ IsSet)) {
      return i;
    }
  }
  return N;
}

}  // namespace jc

void test_find_next() {
  std::bitset<8> b{"10010111"};
  static constexpr int _next_set[] = {1, 2, 4, 4, 7, 7, 7, 8, 8, 8};
  static constexpr int _next_unset[] = {3, 3, 3, 5, 5, 6, 8, 8, 8, 8};

  for (std::size_t i = 0; i < std::size(_next_set); ++i) {
    assert(jc::find_next<true>(b, i) == _next_set[i]);
    assert(jc::find_next<false>(b, i) == _next_unset[i]);
  }
}

void test_find_prev() {
  std::bitset<8> b{"10010110"};
  static constexpr int _prev_set[] = {8, 8, 1, 2, 2, 4, 4, 4, 7, 7};
  static constexpr int _prev_unset[] = {8, 0, 0, 0, 3, 3, 5, 6, 6, 6};

  for (std::size_t i = 0; i < std::size(_prev_set); ++i) {
    assert(jc::find_prev<true>(b, i) == _prev_set[i]);
    assert(jc::find_prev<false>(b, i) == _prev_unset[i]);
  }
}

void test_circular_find_next() {
  std::bitset<8> b{"01010111"};
  static constexpr int _next_set[] = {1, 2, 4, 4, 6, 6, 0, 0, 0, 0};
  static constexpr int _next_unset[] = {3, 3, 3, 5, 5, 7, 7, 3, 3, 3};

  for (std::size_t i = 0; i < std::size(_next_set); ++i) {
    assert(jc::circular_find_next<true>(b, i) == _next_set[i]);
    assert(jc::circular_find_next<false>(b, i) == _next_unset[i]);
  }
}

void test_circular_find_prev() {
  std::bitset<8> b{"10011001"};
  static constexpr int _prev_set[] = {7, 0, 0, 0, 3, 4, 4, 4, 7, 7};
  static constexpr int _prev_unset[] = {6, 6, 1, 2, 2, 2, 5, 6, 6, 6};

  for (std::size_t i = 0; i < std::size(_prev_set); ++i) {
    assert(jc::circular_find_prev<true>(b, i) == _prev_set[i]);
    assert(jc::circular_find_prev<false>(b, i) == _prev_unset[i]);
  }
}

int main() {
  test_find_next();
  test_find_prev();
  test_circular_find_next();
  test_circular_find_prev();
}
#include <cassert>

namespace jc {

template <typename>
struct get_class;

template <typename ClassType, typename MemberType>
struct get_class<MemberType ClassType::*> {
  using type = ClassType;
};

template <typename T>
using get_class_t = typename get_class<T>::type;

template <auto ClassMember>
class Wrapper {
 public:
  Wrapper(get_class_t<decltype(ClassMember)>& obj) : obj_(obj) {}

  void increase() { ++(obj_.*ClassMember); }

 private:
  get_class_t<decltype(ClassMember)>& obj_;
};

struct A {
  int i = 0;
};

}  // namespace jc

int main() {
  jc::A a;
  jc::Wrapper<&jc::A::i>{a}.increase();
  assert(a.i == 1);
}
namespace jc {

template <typename T, typename U>
constexpr auto add(const T& a, const U& b) {
  return a + b;
}

}  // namespace jc

static_assert(jc::add('A', 2) == 'C');

int main() {}

限制

namespace jc {

template <auto N>
struct A {
  static constexpr auto f() { return N; }
};

}  // namespace jc

static_assert(jc::A<42>::f() == 42);
static_assert(jc::A<3.14>::f() == 3.14);  // C++20

int main() {}
namespace jc {

template <const char* s>
struct A {};

}  // namespace jc

constexpr const char* s1 = "hello";  // 内链接对象的指针
extern const char s2[] = "world";    // 外链接
const char s3[] = "down";            // 内链接

int main() {
  static const char s4[] = "demo";  // 无链接
  jc::A<"downdemo">{};              // 错误
  jc::A<s1>{};                      // 错误
  jc::A<s2>{};                      // C++11 允许
  jc::A<s3>{};                      // C++14 允许
  jc::A<s4>{};                      // C++17 允许
}
#include <cassert>

namespace jc {

template <int& N>
struct A {
  A() { ++N; }
  ~A() { --N; }
};

void test() {
  static int n = 0;
  {
    A<n> a;
    assert(n == 1);
  }
  assert(n == 0);
}

}  // namespace jc

int main() { jc::test(); }
namespace jc {

template <int buf[5]>
struct Lexer {};

// template <int* buf>
// struct Lexer {};  // 错误:重定义

template <int fun()>
struct FuncWrap {};

// template <int (*)()>
// struct FuncWrap {};  // 错误:重定义

}  // namespace jc

int main() {}
namespace jc {

template <bool b>
struct A {
  inline static constexpr bool value = b;
};

}  // namespace jc

int main() { static_assert(jc::A<(sizeof(int) > 0)>::value); }

变量模板(Variable Template)

namespace jc {

template <typename T = double>
constexpr T pi{static_cast<T>(3.1415926535897932385)};

static_assert(pi<bool> == true);
static_assert(pi<int> == 3);
static_assert(pi<double> == 3.1415926535897932385);
static_assert(pi<> == 3.1415926535897932385);

}  // namespace jc

int main() {}
#include <array>
#include <cassert>

namespace jc {

template <int N>
std::array<int, N> arr{};

template <auto N>
constexpr decltype(N) x = N;

}  // namespace jc

static_assert(jc::x<'c'> == 'c');

int main() {
  jc::arr<10>[0] = 42;
  assert(jc::arr<10>[0] == 42);
}