【问题标题】:What should I do instead of partial specialization of function templates?我应该怎么做而不是函数模板的部分专业化?
【发布时间】:2014-05-03 07:19:43
【问题描述】:

我想写以下内容:

template <typename S, typename T> void foo() {
    /* code for the general case */
}

template <typename T> void foo<MySType,T>() {
    /* partially specialized code - for any kind of T, but when S is MySType */
}

或者,在其他情况下,如下:

template <typename S, typename T> void bar(const S& a, const T& b) {
    /* code for the general case */
}

template <typename T> void bar<MySType,T>(const MySType& a, const T& b) {
    /* partially specialized code - for any kind of T, but when S is MySType */
}

C++(11) 不允许我这样做。

现在,我读到了this question and its answers;假设我购买了为什么我们没有部分模板专业化的解释(或者只是假设我生活在现实中并且实际上想要编写代码)。好吧,我做什么,而不是?

我真的不想将这些函数包装在一个类中,除非那绝对是我最后的手段。

【问题讨论】:

  • 老实说,我越是深入研究 C++11 和 C++,我就越认为“模板专业化”对于正在发生的事情来说是一种可怕的限定。没有“模板专业化”之类的东西
  • @user2485710:对不起,我不明白……你能详细说明一下吗?或者链接到您更详细地争论过的地方?
  • 模板专业化不仅是一件事,它还是一台图灵完备的机器。不过,它会让你发疯。
  • “专业化”意味着您正在增强已经存在的东西的属性,模板签名能够执行的是类型推断或类型推导,以创建您需要的功能。要专门化你需要至少 1 个已经存在的东西加上至少 1 个属性来增强/更改的东西,我不明白为什么有人会称之为“模板专业化”,而实际上只有一些类型推断和类型推导。有人甚至称这种“过载”为仅在运行时发生的事情。
  • @user2485710:嗯,我认为这是专业化,因为我们对待特殊情况与一般情况不同,仅此而已。

标签: c++ templates template-specialization overloading partial-specialization


【解决方案1】:

超载!重载在各方面都优于专业化。重载解决方案的一部分是选择最专业的重载。只需将“专业化”声明为重载,如果有部分专业化,它将起作用。

不过,请避免使用显式模板参数。您可以改用标签调度。

template< typename t >
struct tag {};

template <typename S, typename T> foo( tag<S>, tag<T> ) {
    /* code for the general case */
}

template <typename T> foo( tag<MyType>, tag<T> ) {
    /* partially specialized code - for any kind of T, but when S is MyType */
}

由于标签为空且按值传递,编译器可能会消除它们对函数调用开销的影响。

【讨论】:

  • OP 的示例构造不佳(缺少返回类型等),但带来了有趣的转折。主要是如何重载没有无参数的东西?
  • @Potatoswatter:所以,如果参数类型中没有表示 S 或 T,您建议添加标记参数以启用重载。当 S 和 T 确实对应参数时,您是否建议也使用这些?
  • @einpoklum 不用担心。它并没有减损问题本身的意义。如果您根深蒂固于类类型种类的专业化,标签调度作为一种解决方案不一定是直观的,所以不要认为您没有考虑到它很奇怪。
  • @einpoklum 如果 S 和 T 是从参数推导出来的,那么标签只会导致麻烦的冗余——参数和标签类型必须匹配,否则会出错。幸运的是,实际参数和标签之间很少重叠。
  • @einpoklum 并回答您的评论,一旦您开始将参数投入混合中,您就可以开始使用真正的重载。 See it live,但你可能已经知道了。
【解决方案2】:

另一种选择是使用帮助类模板,您可以在其中进行部分特化,并使用本身不需要部分特化的包装函数将其隐藏:

#include <iostream>

template<typename S, typename T>
struct foo_helper {
    void foo() {
        std::cout << "general func" << std::endl;        
    }
};

struct MyType {};

template <typename T>
struct foo_helper <MyType,T> {
    void foo() {   
        std::cout << "partially specialized code - for any kind of T, but when S is MyType" << std::endl;
    }
};

template<typename S, typename T>
void foo() {
    foo_helper<S, T>().foo();
}

int main () {
    foo<int, int>();
    foo<int, double>();
    foo<MyType, long>();
}

这也是有效的 C++98/03。

【讨论】:

  • 我能以某种方式自动化/宏化辅助结构的使用吗?
【解决方案3】:

您可能会部分专门化一个辅助结构:

#include <iostream>

namespace Detail {
    template <typename S, typename T>
    struct Foo {
        static void apply() {
            std::cout << "general case\n";
        }
    };
    template <typename T>
    struct Foo<int, T> {
        static void apply() {
            std::cout << "specialized code\n";
        }
    };
}

template <typename S, typename T>
void foo() {
    Detail::Foo<S, T>::apply();
}

int main()
{
    foo<double, double>();
    foo<int, double>();
    return 0;
}

【讨论】:

  • 能否以某种方式实现自动化/简化,这样我就不必总是在命名空间、结构等中明确写入?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-09-12
  • 1970-01-01
相关资源
最近更新 更多