Con*_*tor 6 c++ templates crtp sfinae incomplete-type
以下代码给出了带有和不带*注释的行的不同输出:
#include <iostream>
#include <type_traits>
template <bool>
using bool_void_t = void;
template <typename, typename = void>
struct is_complete : std::false_type
{
};
template <typename T>
struct is_complete<T, bool_void_t<sizeof(T) == sizeof(T)>> : std::true_type
{
};
template <typename Derived>
struct Base
{
static constexpr bool value = is_complete<Derived>{};
// using magic = bool_void_t<value>; // *
};
struct Foo : Base<Foo>
{
};
int main()
{
std::cout << std::boolalpha << Foo::value << std::endl;
}
Run Code Online (Sandbox Code Playgroud)
在这两种情况下,clang ++ 5.0.0用作编译器,编译器标志是-std=c++17 -Wall -Wextra -Werror -pedantic-errors.
clang ++ 5.0.0(-Wall -Wextra -Werror -pedantic-errors)
-std=c++14 -std=c++17
* is commented false true
* is not commented false false
Run Code Online (Sandbox Code Playgroud)g ++ 7.2.1(-Wall -Wextra -Werror -pedantic-errors)
-std=c++14 -std=c++17
* is commented true true
* is not commented false false
Run Code Online (Sandbox Code Playgroud)*被注释(输出是false与-std=c++14编译器标志和true与所述-std=c++17一个)?使用CRTP时遇到的一个常见问题是基类实例化时,派生类不完整。这意味着您不能在派生类中使用成员 typedef 等。
当您考虑一下时,这是有道理的:模板类实际上是一种基于给定模板类型生成新类类型的方法,因此在编译器到达结束}(近似意义上)之前,基类并不完全定义的。如果基类没有完全定义,那么显然派生类也不能完全定义。
因为基类和派生类都是空的(在第一个示例中),所以编译器认为它们是完整的。我想说这是不正确的,但我不是一个期望,也不能确定。is_complete不过,这里的技巧是在定义基类时实例化 的值。派生类完全定义完成后,就完成了。
另外,作为一个重要的示例,请考虑以下内容:
template <typename>
class crtp_traits;
class derived;
template <>
class crtp_traits<derived>
{
public:
using return_type = int;
};
template <typename T>
class base
{
public:
auto get_value() const -> typename crtp_traits<T>::return_type
{
return static_cast<T const*>(this)->do_get_value();
}
};
class derived : public base<derived>
{
public:
auto do_get_value() const -> int
{
return 0;
}
};
Run Code Online (Sandbox Code Playgroud)
derived提供成员 typedef的简单解决方案using return_type = int;将不起作用,因为在尝试访问 typedef 时,派生将不会完成。
| 归档时间: |
|
| 查看次数: |
180 次 |
| 最近记录: |