Is it possible to mark an alias of a type
as final
(i.e. can't be re-defined in derived class)?
#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.
}
According to http://en.cppreference.com/w/cpp/language/final, it is for function only.
Is there a workaround?
It would be useful as a coder fool-proof in some cases.
No, you cannot.
Trait based types could do it, but the machinery is ugly.
Define a distributed type map maybe via an adl based tag function map.
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 {};}
};
now overriding A
's type_tag
works with trait::type<>
but if you try the same with B
you'll get a long incomprehensible error.
This is a bad plan.
Metaclasses will probably let you do something like this as well.
In general, both of these require writing a new sublanguage of C++ to enforce a constraint C++ does not enforce. Possible, but ill-advised unless you have an extemely good reason.