众所周知,类不能从基本类型和标记为 的类继承final。但尽管如此,下面提供的代码在 Clang 12 和 GCC 9 上编译时没有任何问题。
#include <type_traits>
template<typename T>
struct Inheriter : public T{};
int main()
{
std::void_t<Inheriter<int>>();
}
Run Code Online (Sandbox Code Playgroud) 假设我们有一个当前类:
template<typename T>
struct Inheriter : public T {};
Run Code Online (Sandbox Code Playgroud)
T请注意,仅当/未声明为时class,其实例化才是格式正确的。structfinal
然后,借助 SFINAE 的强大功能,std::void_t我们可以在编译时检查类型是格式良好还是格式错误。让我们用它来编写我们自己的简单实现std::is_final:
template<typename T, typename = void>
struct IsFinal : public std::true_type{};
template<typename T>
struct IsFinal<T, std::void_t<decltype(Inheriter<T>{})>> : public std::false_type{};
Run Code Online (Sandbox Code Playgroud)
对于任何任意类型,T编译器都应该实例化最专业的版本IsFinal,如果替换失败,则尝试实例化最不专业的版本。并且只有当所有这些都失败时,编译器才必须吐出错误。
但是在 Clang 14 和 GCC 11.2(目前最新的)上,当我们将某种final类型作为模板参数传递给时IsFinal,我们会收到编译错误(https://godbolt.org/z/q8jxP3Thc)。
为什么编译器不尝试实例化最不专业的版本IsFinal,并直接吐出错误?这是编译器错误还是 C++ 语言标准的某些棘手部分?
c++ metaprogramming sfinae language-lawyer template-meta-programming
我遇到一种情况,我需要从具有相同接口的两个类继承,但要单独覆盖它们,并且我绝对无法调整接口。请参阅下面的代码示例
template<typename T>
struct Foo
{
virtual ~Foo() = default;
virtual void foo() = 0;
};
struct Derived : public Foo<int>, public Foo<double>
{
#if 0 // having something like this would be great, but unfortunately it doesn't work
void Foo<int>::foo() override
{
std::cout << "Foo<int>::foo()" << std::endl;
}
void Foo<double>::foo() override
{
std::cout << "Foo<double>::foo()" << std::endl;
}
#endif
};
Run Code Online (Sandbox Code Playgroud)