是否有可能在编译时强制执行两个派生 类 总是 return 不同的覆盖函数值?
Is it possible to enforce, at compile time, that two derived classes would always return different values for an overriding function?
是否可以在编译时强制执行以下内容:
class B {
public:
virtual constexpr const char* getKeyStr() const = 0;
};
class D1 : public B {
public:
constexpr const char* getKeyStr() const override { return "D1"; }
};
class D2 : public B {
public:
constexpr const char* getKeyStr() const override { return "D2"; }
};
...但是下面不是?我们不希望 D1
和 D2
到 return 相同的密钥字符串:
class B {
public:
virtual constexpr const char* getKeyStr() const = 0;
};
class D1 : public B {
public:
constexpr const char* getKeyStr() const override { return "D1"; }
};
class D2 : public B {
public:
constexpr const char* getKeyStr() const override { return "D1"; } // can we error out here at compile time?
};
澄清:
我在这个例子中只展示了两个派生的 classes,但我想要实现的是 post 这个对任意数量的派生 [=42] 的约束=]es.
要解决的潜在问题:我正在考虑一个serializing/deserializing应用程序,其中每个具有相同基数class的对象将能够生成一个textual/string 将其自身表示写入文件,并且当返回该字符串(我们称之为内容字符串)时,将能够重建相应的数据。
在反序列化过程中,应用程序代码应该能够从内容字符串的关键部分(我们称之为关键字符串)判断出应该重构哪个派生对象。因此,密钥字符串对于每个派生的 class 都必须是唯一的。我知道 type_info::name
可能是唯一的,但它不可定制(或独立于编译器?)。
关于getKeyStr()
函数(对应上面提到的key-string),对于同一个derived的所有objects总是return同一个字符串class.
是的,你可以在编译时检查D1
的getKeyStr
和D2
返回的"strings"是否不同。
首先提供一个在编译时比较2const char *
的函数:
constexpr bool different(const char *x, const char *y)
{
while(*x != '[=10=]' )
if (*x++ != *y++) return true;
return *y != '[=10=]';
}
然后比较返回值:
// this will trigger, if returned strings are the same.
static_assert( different(D1{}.getKeyStr(), D2{}.getKeyStr()) );
编辑:正如@Jarod42 指出的那样,string_view
比较是 constexpr
,因此比较函数可以写得更简单:
constexpr bool different(const char * x, const char * y)
{
return std::string_view{x} != std::string_view{y};
}
这是 demo.
如果你可以得到所有 Derived 类 的列表,你可能会这样做:
template <typename... Ts>
bool have_unique_keys()
{
std::string_view keys[] = {Ts{}.getKeyStr()...}; // requires constexpr default constructor
// static method might be more appropriate
std::sort(std::begin(keys), std::end(keys)); // constexpr in C++20
auto it = std::adjacent_find(std::begin(keys), std::end(keys));
return it != std::end(keys);
}
static_assert(have_unique_keys<>(D1, D2, D3));
是否可以在编译时强制执行以下内容:
class B {
public:
virtual constexpr const char* getKeyStr() const = 0;
};
class D1 : public B {
public:
constexpr const char* getKeyStr() const override { return "D1"; }
};
class D2 : public B {
public:
constexpr const char* getKeyStr() const override { return "D2"; }
};
...但是下面不是?我们不希望 D1
和 D2
到 return 相同的密钥字符串:
class B {
public:
virtual constexpr const char* getKeyStr() const = 0;
};
class D1 : public B {
public:
constexpr const char* getKeyStr() const override { return "D1"; }
};
class D2 : public B {
public:
constexpr const char* getKeyStr() const override { return "D1"; } // can we error out here at compile time?
};
澄清:
我在这个例子中只展示了两个派生的 classes,但我想要实现的是 post 这个对任意数量的派生 [=42] 的约束=]es.
要解决的潜在问题:我正在考虑一个serializing/deserializing应用程序,其中每个具有相同基数class的对象将能够生成一个textual/string 将其自身表示写入文件,并且当返回该字符串(我们称之为内容字符串)时,将能够重建相应的数据。
在反序列化过程中,应用程序代码应该能够从内容字符串的关键部分(我们称之为关键字符串)判断出应该重构哪个派生对象。因此,密钥字符串对于每个派生的 class 都必须是唯一的。我知道
type_info::name
可能是唯一的,但它不可定制(或独立于编译器?)。关于
getKeyStr()
函数(对应上面提到的key-string),对于同一个derived的所有objects总是return同一个字符串class.
是的,你可以在编译时检查D1
的getKeyStr
和D2
返回的"strings"是否不同。
首先提供一个在编译时比较2const char *
的函数:
constexpr bool different(const char *x, const char *y)
{
while(*x != '[=10=]' )
if (*x++ != *y++) return true;
return *y != '[=10=]';
}
然后比较返回值:
// this will trigger, if returned strings are the same.
static_assert( different(D1{}.getKeyStr(), D2{}.getKeyStr()) );
编辑:正如@Jarod42 指出的那样,string_view
比较是 constexpr
,因此比较函数可以写得更简单:
constexpr bool different(const char * x, const char * y)
{
return std::string_view{x} != std::string_view{y};
}
这是 demo.
如果你可以得到所有 Derived 类 的列表,你可能会这样做:
template <typename... Ts>
bool have_unique_keys()
{
std::string_view keys[] = {Ts{}.getKeyStr()...}; // requires constexpr default constructor
// static method might be more appropriate
std::sort(std::begin(keys), std::end(keys)); // constexpr in C++20
auto it = std::adjacent_find(std::begin(keys), std::end(keys));
return it != std::end(keys);
}
static_assert(have_unique_keys<>(D1, D2, D3));