如果参数具有成员变量,则对函数进行专门化 [英] Specialize function if argument has member variable

查看:248
本文介绍了如果参数具有成员变量,则对函数进行专门化的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个模板化的错误报告功能,因为它可以报告许多不同消息类别的错误:

I have a function for error reporting that is templated because it can report errors for many different message classes:

template <typename MSG>
void reportErr(const MSG& msg)
{
    std::cout << "ERROR: " << msg.error << std::endl;
}

但是,某些类型的消息具有可以报告的更详细的错误或其他专门的错误报告,例如

However, some types of message have more detailed error that can be reported or other specialized error reporting, e.g.

template<>
void reportErr(const SpecificMsg& msg)
{
    std::cout << "ERROR: " << msg.error;
    std::cout << ", details: " << msg.details << std::endl;
}

由于有许多类型,例如SpecificMsg,因此我不想为每种类型创建单独的模板专业化.是否可以为具有.details成员变量的任何类型创建通用专业化/部分专业化?

Since there are many types like SpecificMsg, I'd rather not create an individual template specialization for each type. Is it possible to create a generic specialization/partial specialization for any type that has a .details member variable?

如果可能的话,我希望有一种一般的方法(因此,如果一个专业化名称为.details,则是一种专业化,如果它是.other_info,则为另一种专业化,等等).

If possible, I'd like a way to do this generally (so one specialization if it has .details, a different one if it has .other_info, etc).

编辑:这是明确询问有关功能的问题.我见过的代码可以做类似的事情来专门化模板 classes ,但是我从未遇到过能满足非成员函数要求的事情.我怀疑将用于类的方法转换为可用于函数的方法并不难,但我一直无法弄清楚如何做到这一点.

Edit: This is explicitly asking about functions. I've seen code that does similar things to specialize template classes, but I've never encountered something that does what I want for non-member functions. I suspect it isn't hard to convert the approach used for classes to work for functions, but I haven't been able to figure out how to do it.

编辑2 :我的gcc版本(4.6.3)似乎不支持完整的C ++ 11标准,因此 void_t 选项对我不起作用.我的编译器抱怨'type'之前的嵌套名称说明符"等,甚至不允许我定义void_t.因此,我从问题中删除了C ++ 11标记.

Edit 2: my version of gcc (4.6.3) appears not to support the full C++11 standard, so the void_t option mentioned in the "duplicate" question doesn't work for me. My compiler complains "expected nested-name-specifier before 'type'" etc and won't even let me define void_t. As such, I've removed the C++11 tag from my question.

推荐答案

如果可能的话,我希望有一种通常的方法(因此,一个专业化如果具有.details,则不同,而另一个专业化则具有.other_info等).

If possible, I'd like a way to do this generally (so one specialization if it has .details, a different one if it has .other_info, etc).

如果得到您的期望,您可以将choice-技巧与decltype结合使用,如以下示例所示:

If I got your expectation, you can use the choice-trick combined with decltype as it happens in the following example:

#include <iostream>

template<int N>
struct choice: choice<N-1> {};

template<>
struct choice<0> {};

struct Foo { int error; };
struct Bar { int error; int details; };
struct Quux { int error; char other_info; };

template<typename MSG>
auto reportErr(choice<2>, const MSG& msg) -> decltype(msg.details, void()) {
    std::cout << "ERROR: " << msg.error;
    std::cout << ", details: " << msg.details << std::endl;
}

template<typename MSG>
auto reportErr(choice<1>, const MSG& msg) -> decltype(msg.other_info, void()) {
    std::cout << "ERROR: " << msg.error;
    std::cout << ", other_info: " << msg.other_info << std::endl;
}

template <typename MSG>
void reportErr(choice<0>, const MSG& msg) {
    std::cout << "ERROR: " << msg.error << std::endl;
}

template <typename MSG>
void reportErr(const MSG &msg) {
    reportErr(choice<100>{}, msg);
}

int main() {
    reportErr(Foo{0});
    reportErr(Bar{0, 42});
    reportErr(Quux{0, 'c'});
}

查看并在 wandbox 上运行(实际上使用的是GCC 4.5.4,您提到的不可用).它利用重载解析根据消息的类型选择功能的工作版本,并丢弃两者之间的所有内容.您可以添加更多的 specializations (即使它们毕竟不是正确的 specializations ,也可以这样称呼它们),并根据您的喜好对它们进行排序,方法是将choice参数调整为必需(其值越高,专业化的优先级越高).

See it up and running on wandbox (using GCC 4.5.4 actually, the version you mentioned isn't available). It exploits overloading resolution to pick up a working version of the function according to the type of the message and discards all what's in between. You can add more specializations (let's call them so, even though they are not properly specializations after all) and sort them according to your preferences by adjusting the choice parameter as needed (the higher its value, the higher the priority of the specialization).

在与我上面显示的类似的基于SFINAE的解决方案中,将choice-技巧与sizeof组合在一起也可以实现类似的目的. 特别是,这是一个有效的示例:

Something similar can also be done by combining the choice-trick with sizeof in a SFINAE'd based solution similar to what I shown above.
In particular, here is a working example:

#include <iostream>

template<int N>
struct choice: choice<N-1> {};

template<>
struct choice<0> {};

struct Foo { int error; };
struct Bar { int error; int details; };
struct Quux { int error; char other_info; };

template<typename MSG, std::size_t = sizeof(MSG::details)>
void reportErr(choice<2>, const MSG& msg) {
    std::cout << "ERROR: " << msg.error;
    std::cout << ", details: " << msg.details << std::endl;
}

template<typename MSG, std::size_t = sizeof(MSG::other_info)>
void reportErr(choice<1>, const MSG& msg) {
    std::cout << "ERROR: " << msg.error;
    std::cout << ", other_info: " << msg.other_info << std::endl;
}

template <typename MSG>
void reportErr(choice<0>, const MSG& msg) {
    std::cout << "ERROR: " << msg.error << std::endl;
}

template <typename MSG>
void reportErr(const MSG &msg) {
    reportErr(choice<100>{}, msg);
}

int main() {
    reportErr(Foo{0});
    reportErr(Bar{0, 42});
    reportErr(Quux{0, 'c'});
}

wandbox 上运行它.优点是该解决方案不会受到您在上一个解决方案中收到的烦人警告的困扰.

See it up and running on wandbox. The advantage is that this solution doesn't suffer from the annoying warning you receive with the previous one.

我用比您要求的版本更旧的编译器(GCC 4.5.4)对其进行了测试,因此我非常有信心它们都可以在GCC 4.6.x中使用.

I tested it with an older compiler than what you asked (GCC 4.5.4), so I'm pretty confident they both work also with GCC 4.6.x.

这篇关于如果参数具有成员变量,则对函数进行专门化的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆