簡體   English   中英

如何使用非模板派生的 class 制作非類型模板基礎 class

[英]How to make a non-type template base class with non-template derived class

是否可以有一個模板基礎 class 和一個非模板派生的 class? 如果是這樣,如果基礎 class 是非類型模板怎么辦?

我正在嘗試將 constexpr 字符串傳遞給非模板派生的 class,但想在 class 的編譯期間檢查該字符串。 如果我將 class 設為模板,我可以讓它工作,但如果不是模板,有沒有辦法做到這一點?

我希望可以工作的一個例子:

template<const char* name>
class Base
{
public:
    constexpr Base(){
        someFunction(name);
    }

    const char* base_name = name;
};

class Derived: public Base
{
public:
    constexpr Derived(const char* name)
    {
        Base<name>();
    }

}

是否可以有一個模板基礎 class 和一個非模板派生的 class?

是的,請參見下面示例中的AAABBBCCC

如果是這樣,如果基礎 class 是非類型模板怎么辦?

請參閱下面示例中的DDDEEEFFF

在 C++20 中,您可以擁有某種字符串文字模板 arguments。 這個頁面給出了一個關於它們的使用的簡明例子。

我不確定您的意圖,以及在您的用例中應該是constexpr還是 dynamic,但這是一個嘗試。 由於static_assert() ,在編譯時會檢查字符串文字的某些屬性。

/**
  g++ -std=c++20 -o prog_cpp prog_cpp.cpp \
      -pedantic -Wall -Wextra -Wconversion -Wno-sign-conversion \
      -g -O0 -UNDEBUG -fsanitize=address,undefined
**/

#include <iostream>
#include <algorithm> // std::copy_n()

template<typename T> class AAA { public: T member; };
class BBB: public AAA<int> { };
class CCC: public AAA<double> { };

template<int N> class DDD { public: static constexpr int value=N; };
class EEE: public DDD<100> { };
class FFF: public DDD<1000> { };

template<size_t N>
struct StringLiteral
{
  constexpr StringLiteral(const char (&str)[N]) { std::copy_n(str, N, value); }    
  char value[N];
};

constexpr bool someFunction(const char *n) { return n[0]<n[1]; }

template<StringLiteral name>
class Base
{
public:
  static constexpr const char* base_name=name.value;
  constexpr Base() { static_assert(someFunction(base_name)); }
};

class Derived1: public Base<"def">
{
public:
  constexpr Derived1(int i): Base{}, i_{i} { }
  void f() { i_+=1; std::cout << base_name << ' ' << i_ << '\n'; }
private:
  int i_;
};

class Derived2: public Base<"ghi">
{
public:
  constexpr Derived2(int i): Base{}, i_{i} { }
  void f() { i_+=2; std::cout << base_name << ' ' << i_ << '\n'; }
private:
  int i_;
};

/*
class BadDerived3: public Base<"jhi"> // static_assert() fails
{
public:
  constexpr BadDerived3(int i): Base{}, i_{i} { }
  void f() { i_+=3; std::cout << base_name << ' ' << i_ << '\n'; }
private:
  int i_;
};
*/

int
main()
{
  AAA<char> aaa{'A'};
  BBB bbb{123};
  CCC ccc{45.67};
  std::cout << aaa.member << ' '
            << bbb.member << ' '
            << ccc.member << '\n'; // displays    A 123 45.67
  DDD<10> ddd{};
  EEE eee{};
  FFF fff{};
  std::cout << ddd.value << ' '
            << eee.value << ' '
            << fff.value << '\n'; // displays    10 100 1000
  // Base<"zbc"> bad_b; // static_assert() fails
  Base<"abc"> b;
  Derived1 d1{10};
  Derived2 d2{20};
  d1.f(); // displays   def 11
  d2.f(); // displays   ghi 22
  return 0;
}

編輯

在對 C++20 支持發表評論后,這里是一個修改版本,適用於 C++11。 我們不能提供我們自己的類型作為模板參數,但允許引用。 訣竅是使用 static 存儲創建一個類似constexpr的字符串數據,並將其作為模板參數引用。 這不像 C++20 版本那樣舒服,但它仍然可以使用,因為每個派生的 class 只需要它之前的constexpr名稱。 所有這一切都是無恥地從這個頁面上的各種答案中得到啟發。

/**
  g++ -std=c++11 -o prog_cpp prog_cpp.cpp \
      -pedantic -Wall -Wextra -Wconversion -Wno-sign-conversion \
      -g -O0 -UNDEBUG -fsanitize=address,undefined
**/

#include <iostream>

struct constexpr_str
{
  const char* const data;
  const std::size_t size;
  template<std::size_t N>
  constexpr constexpr_str(const char(&d)[N]) : data{d}, size{N-1} { }
};

constexpr bool someFunction(constexpr_str n) { return n.data[0]<n.data[1]; }

template<const constexpr_str &name>
class Base
{
public:
  static constexpr constexpr_str base_name{name};
  constexpr Base() { static_assert(someFunction(base_name), "bad_name"); }
};

constexpr auto derived1_name=constexpr_str{"def"};
class Derived1: public Base<derived1_name>
{
public:
  constexpr Derived1(int i): Base{}, i_{i} { }
  void f() { i_+=1; std::cout << base_name.data << ' ' << i_ << '\n'; }
private:
  int i_;
};

constexpr auto derived2_name=constexpr_str{"ghi"};
class Derived2: public Base<derived2_name>
{
public:
  constexpr Derived2(int i): Base{}, i_{i} { }
  void f() { i_+=2; std::cout << base_name.data << ' ' << i_ << '\n'; }
private:
  int i_;
};

/*
constexpr auto derived3_name=constexpr_str{"jhi"};
class BadDerived3: public Base<derived3_name> // static_assert() fails
{
public:
  constexpr BadDerived3(int i): Base{}, i_{i} { }
  void f() { i_+=3; std::cout << base_name.data << ' ' << i_ << '\n'; }
private:
  int i_;
};
*/

constexpr auto bad_base_name=constexpr_str{"zbc"};
constexpr auto base_name=constexpr_str{"abc"};

int
main()
{
  constexpr auto txt=constexpr_str{"ABCD"};
  static_assert(txt.size==4, "incorrect size");
  static_assert(txt.data[1]=='B', "incorrect char");
  // Base<bad_base_name> bad_b; // static_assert() fails
  Base<base_name> b;
  Derived1 d1{10};
  Derived2 d2{20};
  d1.f(); // displays   def 11
  d2.f(); // displays   ghi 22
  return 0;
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM