template<typename T, typename value_type>
class CRTPBase {
using CRTPBase_value = value_type;
...
}
template<typename T>
class derived_1: public CRTPBase<derived_1, derived_type_1>{
...
}
template<typename T>
class derived_2: public CRTPBase<derived_2, derived_type_2>{
...
}
template<typename T>
class derived_3: public CRTPBase<derived_3, derived_type_3>{
...
}
template<typename T>
class derived_4: public CRTPBase<derived_4, derived_type_4>{
...
}
template <typename T>
struct fmt::formatter<derived_1<T>>{
template <typename ParseContext>
constexpr auto parse(ParseContext& ctx){
return begin(ctx);
}
template <typename FormatContext>
auto format(const derived_1<T>& v, FormatContext& ctx)
{
auto&& out= ctx.out();
if(v.height() > 1){
format_to(out, "[\n");
}
for(std::size_t i = 0; i < v.height(); ++i){
format_to(out, "[");
for(std::size_t j = 0; j < v.width(); ++j){
format_to(out, ", ", v(i,j));
}
format_to(out, "]\n");
}
if(v.height() > 1){
return format_to(out, "]\n");
}
return out;
}
};
这非常适合
derived_1 d = ...;
fmt::print("{}", d);
然后我试着看看我是否可以用CRTP基来专门化
template <typename T>
struct fmt::formatter<CRTPBase<T, T::derived_type>>{
template <typename FormatContext>
auto format(const CRTPBase<T, T::derived_type>& v, FormatContext& ctx)
}
这不起作用,我得到“静态断言失败:不知道如何格式化类型”,两个类型之间没有有效的转换,我想这是因为显式模板转换问题。我试着
template <typename T>
struct fmt::formatter<CRTPBase<T, T::derived_type>>{
template <typename FormatContext>
auto format(const T& v, FormatContext& ctx)
}
template<class Derived_T>
using derived_element_wise = decltype(Derived_T::CRTPBase_value);
template<class Derived_T>
using is_CRTP_derived = std::experimental::is_detected<derived_element_wise, Derived_T>
template <typename T, typename U = enable_if_t<is_CRTP_derived<T>::value>>
struct fmt::formatter<T>{
template <typename FormatContext>
auto format(const T& v, FormatContext& ctx)
}
我得到了一个关于“模板参数在部分专门化中不可推导”的错误:好吧,所以接下来我尝试
template <typename T>
struct fmt::formatter<T,enable_if_t<is_CRTP_derived<T>::value>>{
template <typename FormatContext>
auto format(const T& v, FormatContext& ctx)
}
似乎完全跳过类型,我得到我得到“静态断言失败:不知道如何格式化类型”。所以我试着
template <typename T>
struct fmt::formatter<enable_if_t<is_CRTP_derived<T>::value, T>>{
template <typename FormatContext>
auto format(const T& v, FormatContext& ctx)
}
我得到了“错误:模板参数在部分专门化中不可推导”,然后我尝试
template <typename T>
struct fmt::formatter<T>{
using temp = enable_if_t<is_CRTP_derived<T>::value>;
template <typename FormatContext>
auto format(const T& v, FormatContext& ctx)
}
//main.cpp
#include <fmt/format.h>
#include <fmt/core.h>
#include <experimental/type_traits>
#include <type_traits>
//change 0->6 to see errors of each attempt
#define ATTEMPT 0
template<class Derived_T>
using derived_element_wise = decltype(Derived_T::CRTPBase_value);
template<class Derived_T>
using is_CRTP_derived = std::experimental::is_detected<derived_element_wise, Derived_T>;
template<typename T, typename value_type>
struct CRTPBase {
using CRTPBase_value = value_type;
std::size_t size(){
auto derived = static_cast<const T*>(this);
return derived->width() * derived->height();
}
};
template<typename T>
struct derived_1: public CRTPBase<derived_1<T>, typename std::remove_const<T>::type>{
using derived_type = T;
std::size_t width() const{
return 1;
}
std::size_t height() const{
return 1;
}
};
template<typename T>
struct derived_2: public CRTPBase<derived_2<T>, typename std::remove_const<T>::type>{
using derived_type = T;
std::size_t width() const{
return 2;
}
std::size_t height() const{
return 2;
}
};
template<typename T>
struct derived_3: public CRTPBase<derived_3<T>, typename std::remove_const<T>::type>{
using derived_type = T;
std::size_t width() const{
return 3;
}
std::size_t height() const{
return 3;
}
};
template<typename T>
struct derived_4: public CRTPBase<derived_4<T>, typename std::remove_const<T>::type>{
using derived_type = T;
std::size_t width() const{
return 4;
}
std::size_t height() const{
return 4;
}
};
#if ATTEMPT == 0
// Example properly working printer
template <typename T>
struct fmt::formatter<derived_1<T>>{
template <typename ParseContext>
constexpr auto parse(ParseContext& ctx){
return begin(ctx);
}
template <typename FormatContext>
auto format(const derived_1<T>& v, FormatContext& ctx)
{
auto&& out= ctx.out();
if(v.height() > 1){
format_to(out, "[\n");
}
for(std::size_t i = 0; i < v.height(); ++i){
format_to(out, "[");
for(std::size_t j = 0; j < v.width(); ++j){
format_to(out, "{},", 0);
}
format_to(out, "]\n");
}
if(v.height() > 1){
return format_to(out, "]\n");
}
return out;
}
};
template <typename T>
struct fmt::formatter<derived_2<T>>{
template <typename ParseContext>
constexpr auto parse(ParseContext& ctx){
return begin(ctx);
}
template <typename FormatContext>
auto format(const derived_2<T>& v, FormatContext& ctx)
{
auto&& out= ctx.out();
if(v.height() > 1){
format_to(out, "[\n");
}
for(std::size_t i = 0; i < v.height(); ++i){
format_to(out, "[");
for(std::size_t j = 0; j < v.width(); ++j){
format_to(out, "{},", 0);
}
format_to(out, "]\n");
}
if(v.height() > 1){
return format_to(out, "]\n");
}
return out;
}
};
template <typename T>
struct fmt::formatter<derived_3<T>>{
template <typename ParseContext>
constexpr auto parse(ParseContext& ctx){
return begin(ctx);
}
template <typename FormatContext>
auto format(const derived_3<T>& v, FormatContext& ctx)
{
auto&& out= ctx.out();
if(v.height() > 1){
format_to(out, "[\n");
}
for(std::size_t i = 0; i < v.height(); ++i){
format_to(out, "[");
for(std::size_t j = 0; j < v.width(); ++j){
format_to(out, "{},", 0);
}
format_to(out, "]\n");
}
if(v.height() > 1){
return format_to(out, "]\n");
}
return out;
}
};
template <typename T>
struct fmt::formatter<derived_4<T>>{
template <typename ParseContext>
constexpr auto parse(ParseContext& ctx){
return begin(ctx);
}
template <typename FormatContext>
auto format(const derived_4<T>& v, FormatContext& ctx)
{
auto&& out= ctx.out();
if(v.height() > 1){
format_to(out, "[\n");
}
for(std::size_t i = 0; i < v.height(); ++i){
format_to(out, "[");
for(std::size_t j = 0; j < v.width(); ++j){
format_to(out, "{},", 0);
}
format_to(out, "]\n");
}
if(v.height() > 1){
return format_to(out, "]\n");
}
return out;
}
};
#elif ATTEMPT == 1
template <typename T>
struct fmt::formatter<CRTPBase<T, typename T::derived_type>>{
template <typename ParseContext>
constexpr auto parse(ParseContext& ctx){
return begin(ctx);
}
template <typename FormatContext>
auto format(const CRTPBase<T, typename T::derived_type>& v, FormatContext& ctx)
{
auto&& out= ctx.out();
if(v.height() > 1){
format_to(out, "[\n");
}
for(std::size_t i = 0; i < v.height(); ++i){
format_to(out, "[");
for(std::size_t j = 0; j < v.width(); ++j){
format_to(out, "{},", 0);
}
format_to(out, "]\n");
}
if(v.height() > 1){
return format_to(out, "]\n");
}
return out;
}
};
#elif ATTEMPT == 2
template <typename T>
struct fmt::formatter<CRTPBase<T, typename T::derived_type>>{
template <typename ParseContext>
constexpr auto parse(ParseContext& ctx){
return begin(ctx);
}
template <typename FormatContext>
auto format(const T& v, FormatContext& ctx)
{
auto&& out= ctx.out();
if(v.height() > 1){
format_to(out, "[\n");
}
for(std::size_t i = 0; i < v.height(); ++i){
format_to(out, "[");
for(std::size_t j = 0; j < v.width(); ++j){
format_to(out, "{},", 0);
}
format_to(out, "]\n");
}
if(v.height() > 1){
return format_to(out, "]\n");
}
return out;
}
};
#elif ATTEMPT == 3
template <typename T, typename U = std::enable_if_t<is_CRTP_derived<T>::value>>
struct fmt::formatter<T>{
template <typename ParseContext>
constexpr auto parse(ParseContext& ctx){
return begin(ctx);
}
template <typename FormatContext>
auto format(const T& v, FormatContext& ctx)
{
auto&& out= ctx.out();
if(v.height() > 1){
format_to(out, "[\n");
}
for(std::size_t i = 0; i < v.height(); ++i){
format_to(out, "[");
for(std::size_t j = 0; j < v.width(); ++j){
format_to(out, "{},", 0);
}
format_to(out, "]\n");
}
if(v.height() > 1){
return format_to(out, "]\n");
}
return out;
}
};
#elif ATTEMPT == 4
template <typename T>
struct fmt::formatter<T,std::enable_if_t<is_CRTP_derived<T>::value>>{
template <typename ParseContext>
constexpr auto parse(ParseContext& ctx){
return begin(ctx);
}
template <typename FormatContext>
auto format(const T& v, FormatContext& ctx)
{
auto&& out= ctx.out();
if(v.height() > 1){
format_to(out, "[\n");
}
for(std::size_t i = 0; i < v.height(); ++i){
format_to(out, "[");
for(std::size_t j = 0; j < v.width(); ++j){
format_to(out, "{},", 0);
}
format_to(out, "]\n");
}
if(v.height() > 1){
return format_to(out, "]\n");
}
return out;
}
};
#elif ATTEMPT == 5
template <typename T>
struct fmt::formatter<std::enable_if_t<is_CRTP_derived<T>::value, T>>{
template <typename ParseContext>
constexpr auto parse(ParseContext& ctx){
return begin(ctx);
}
template <typename FormatContext>
auto format(const T& v, FormatContext& ctx)
{
auto&& out= ctx.out();
if(v.height() > 1){
format_to(out, "[\n");
}
for(std::size_t i = 0; i < v.height(); ++i){
format_to(out, "[");
for(std::size_t j = 0; j < v.width(); ++j){
format_to(out, "{},", 0);
}
format_to(out, "]\n");
}
if(v.height() > 1){
return format_to(out, "]\n");
}
return out;
}
};
#elif ATTEMPT == 6
template <typename T>
struct fmt::formatter<T>{
using temp = std::enable_if_t<is_CRTP_derived<T>::value>;
template <typename ParseContext>
constexpr auto parse(ParseContext& ctx){
return begin(ctx);
}
template <typename FormatContext>
auto format(const T& v, FormatContext& ctx)
{
auto&& out= ctx.out();
if(v.height() > 1){
format_to(out, "[\n");
}
for(std::size_t i = 0; i < v.height(); ++i){
format_to(out, "[");
for(std::size_t j = 0; j < v.width(); ++j){
format_to(out, "{},", 0);
}
format_to(out, "]\n");
}
if(v.height() > 1){
return format_to(out, "]\n");
}
return out;
}
};
#endif
int main(){
derived_1<int> d1;
derived_2<float> d2;
derived_3<bool> d3;
derived_4<double> d4;
fmt::print("{}", d1);
fmt::print("{}", d2);
fmt::print("{}", d3);
fmt::print("{}", d4);
return 0;
}
您可以使用sfinae完成以下操作:
template <typename T>
struct fmt::formatter<
T, std::enable_if_t<
std::is_base_of_v<CRTPBase<T, typename T::derived_type>, T>, char>> {
auto parse(format_parse_context& ctx) { return ctx.begin();}
template <typename FormatContext>
auto format(const T& v, FormatContext& ctx) {
// Format v and write the output to ctx.out().
return ctx.out();
}
};
下面是一个完整的Godbolt工作示例:https://godbolt.org/z/vsbcc8。
在{fmt}文档中还有一个这样做的示例:https://fmt.dev/lates/api.html#formatting-user-defined-types。
还尝试在专门化的中进行模板方法专门化: 这一次它编译,但调用原始方法,即 解决方案
关于下一个代码,我有一些问题: > 类专业化
这个问题可能太难在标题中的on句子中描述,但这里有一个最小的例子: 当两种类型相同时 当这两种类型是同一类型的类模板的实例化时 天真地说,我们希望第二个部分专门化不会与第一个不明确,因为它感觉“更专门化”,对基础模板上和的推导类型施加更多限制。然而,主要的编译器似乎同意我们的期望是错误的:为什么它不被认为是更专业化的?
我有一个模板函数doSomething(T),它接受任何类型的参数…类型基类除外。 所以我把doSomething模板专门用于类型Base的参数,所以它做了一些不同的事情。 然而,当我将派生类传递给doSomething时,它会打印“所有类型!”,而我希望它打印“Base!”,因为派生类本质上也是一个基类。 如果我有: 然后doSomething(d)也会打印“所有类型!”而不是“base!”,因
我有一个通用算法,需要访问其模板类型的特征。有一个特征类可以专门用于提供这些特征。 在我的类中使用此算法时,我想将其与类中定义的私有类型一起使用。 然而,专门化只能发生在或全局范围内,而我的类是不可访问的。 是否有可能以某种方式专门化具有私有类型的模板,至少在可访问此类型的范围内? 也许可以将这个专门化声明为一个类?
我有以下模板方法: 但是我得到了那些奇怪的链接错误: /usr/lib/gcc/x86_64-redhat-linux/4.4。7/../../../../包括/c/4.4。7/例外:62:void MyStruct::readField(std::basic_istream)的多重定义 如何专门化此成员函数? 编辑 这种方法在以下方面起作用: 或者使用s或在类外使用