使"typedef"成为最终的(或模拟它)
Make a "typedef" be final (or simulate it)
是否可以将type
的别名标记为final
(即不能在派生类中重新定义)?
#include <iostream>
class B{
public: using type=std::string;
};
class D : public B{
public: using type=int; //<--- [1] I want a compile error here.
};
int main(){
typename D::type str="abc"; //<--- [2] This line is actually correct.
}
根据http://en.cppreference.com/w/cpp/language/final,仅用于功能
有变通办法吗?
在某些情况下,它将作为一个程序员的傻瓜证明是有用的。
不,不能。
基于特质的类型可以做到这一点,但机器很难看。
可以通过基于adl的标记函数映射来定义分布式类型映射。
template<class T>struct tag_t{constexpr tag_t(){} using type=T;};
template<class T>constexpr tag_t<T> tag{};
namespace trait {
template<class T>
constexpr void type_tag( tag_t<T> ){}
template<class T>
using type=typename decltype( type_tag( tag<T> ) )::type;
}
// non-final alias
struct A{
friend constexpr tag_t<int> type_tag(tag_t<A>){return {};}
};
// non-final alias
struct A{
friend constexpr tag_t<char> type_tag(tag_t<A>){return {};}
};
// final alias
struct B{
template<class T, std::enable_if_t< std::is_base_of<B,T>{}, bool> =true>
friend constexpr tag_t<std::string> type_tag(tag_t<T>){return {};}
};
现在,重写A
的type_tag
可以与trait::type<>
一起使用,但如果您对B
进行同样的尝试,您将得到一个长期无法理解的错误。
这是一个糟糕的计划。
元类可能也会让你做这样的事情。
一般来说,这两者都需要编写一个新的C++子语言来强制执行C++没有强制执行的约束。可能,但不明智,除非你有一个非常好的理由。
关于如何使用枚举或其他伪对象有效隐藏类型的切向答案。
/*
* Imagine everybody uses managed strings in our project throughout,
* so everyone expects to be able to declare and print strings everywhere,
* especially for debugging...
*/
typedef OurInternalMangedStrings string;
/***/
void InternalStringManager::ReallyDoingNastyInternalStuff()
{
// Within this code casually using managed strings
// to format error messages, etc,
// would be fatal as it will cause nasty recursion.
enum DoNotUseStrings_DeadlockDanger { string, OurInternalMangedStrings };
printError(string ("I had an error here and I don't know why - code ") << errCode);
}
这将产生一个错误,有望同时提到字符串和DoNotUseStrings_DeadlockDanger,从而提供线索。
但它对类型的用途有限,因为它虽然阻止了作者使用"字符串"一词,但并不能阻止代码自动执行转换,或使用已经存在的该类型的对象,例如,如果构造函数不明确,则以下内容将无注释通过:
printError("I had an error here and I don't know why at all!");
对于数据值,我发现它更有用:
void MyManager::Setup()
{
{ SomeFeature newPimple = new Somefeature;
enum DoNotUseMember {someFeature};
/** set up newPimple using other member data and parameters
when it is ready I will assign it to the member variable "someFeature"
**/
/** any accidental use of a someFeature member will produce error message **/
// Ready to install the new pimpl as the visible feature
MUTEX_RAII(access_feature); // ... Or whatever might be needed
/* can still access someFeature by being explicit */
delete this->someFeature;
this->someFeature = newPimpl;
}
/** other setup code that uses the new feature **/
}
就我个人而言,我会将新实例称为someFeature,并免费获得隐藏行为,但许多人发现这个名称很难重复使用。
我使用这种技术的另一种方式是重构。我有一个方法,可以愉快地使用成员值来控制其行为,然后需要一个增强,其中一个控制值必须由外部控制。为了实现这一点,原始的无参数方法变成了一个填充程序,调用一个以成员为参数的新方法。
但是,如何确保新方法不会意外地使用成员而不是参数呢?就我个人而言,我会让争论掩盖成员,但我们再次受到他人理解的限制。
- C++:TypeDef使用元组
- 如何使用Google Mock来模拟gettimeofday()
- G锁定铸造到基础上会释放模拟行为
- 有什么好的方法可以让系统调用代理允许在单元测试中进行模拟
- 有没有一种方法可以通过"typedef"为重新定义的基本类型定义特征和强制转换运算符
- 落砂模拟碰撞检测C++和SFML
- 在gtest.中使用fff.h模拟系统API
- 为什么在使用typedef时类推导指南会失败
- 谷歌模拟和覆盖关键字
- 用C#中的并集模拟C++嵌套结构
- 在同一模拟中使用静脉和静脉_ inet内容时出现运行时错误
- 在模拟器中使用并集来模拟CPU寄存器有多合适
- 我写了一个C++程序来模拟Enigma机器.我没有得到输出
- 尝试根据类中 typedef 的存在来专门化模板函数
- 如何重新定义MPI_FLOAT,MPI_DOUBLE以 typedef 的方式
- typedef 枚举和枚举类有什么区别?
- 如何模拟不同边数的骰子滚动?
- 在类模板中使用 typedef 时出错
- 模板类中的 typedef 语句
- 使"typedef"成为最终的(或模拟它)