[英]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?
是的,請參見下面示例中的AAA
、 BBB
、 CCC
。
如果是這樣,如果基礎 class 是非類型模板怎么辦?
請參閱下面示例中的DDD
、 EEE
、 FFF
。
在 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.