14

你好!

我只想专门化两种模板类型中的一种。例如template <typename A, typename B> class X,应该对单个函数有一个特殊的实现X<float, sometype>::someFunc()

示例代码:

主.h:

#include <iostream>

template <typename F, typename I>
class B
{
public:
    void someFunc()
    {
        std::cout << "normal" << std::endl;
    };

    void someFuncNotSpecial()
    {
        std::cout << "normal" << std::endl;
    };
};

template <typename I>
void B<float, I>::someFunc();

主.cpp:

#include <iostream>
#include "main.h"

using namespace std;

template <typename I>
void B<float, I>::someFunc()
{
    cout << "special" << endl;
}

int main(int argc, char *argv[])
{
    B<int, int> b1;
    b1.someFunc();
    b1.someFuncNotSpecial();

    B<float, int> b2;
    b2.someFunc();
    b2.someFuncNotSpecial();
}

编译失败class B。这是真的吗,这在 C++ 中是不可能的吗?最好的解决方法是什么?

[编辑]

template <float, typename I> void B<float, I>::someFunc();导致 main.h:26: 错误:'float' 不是模板常量参数的有效类型

template <typename I> void B<float, I>::someFunc();导致 main.h:27: 错误:无效使用不完整类型 'class B'</p>

我正在使用 gcc。

[编辑]

我不想专门化整个班级,因为还有其他没有专门化的功能。

4

4 回答 4

22

您必须提供类模板的部分专业化B

template <typename I>
class B<float, I>
{
public:
    void someFunc();
};

template <typename I>
void B<float, I>::someFunc()
{
    ...
}

您也可以只someFunc在专业化内部定义。

但是,如果您只想专门化一个函数,而不是一个类,例如

template <typename F, typename I>
void someFunc(F f, I i) { someFuncImpl::act(f, i); }

template <typename F, typename I>
struct someFuncImpl { static void act(F f, I i) { ... } };

// Partial specialization
template <typename I>
struct someFuncImpl<float, I> { static void act(float f, I i) { ... } };

但是如果没有这个技巧,你就不能专门化一个函数模板。

于 2010-09-22T11:51:06.623 回答
6

尽管您可以完全 特化类模板的成员函数,但不能_部分特化成员函数。- 安德烈亚历山德雷斯库

部分专业化由其他海报解释。

但是,您可以使用重载:

template <class T, class U> T fun(U obj); // primary template
template <class U> void Fun<void, U>(U obj); // illegal pertial
// specialization
template <class T> T fun (Window obj); // legal (overloading)

如果你想深入了解这个问题,可以在 A. Alexandrescu 的“现代 C++ 设计”中深入阅读这个问题。

于 2010-09-22T12:09:14.680 回答
0

解决方案 1. 将所有实现移至 B_Base 等基类。然后专注于浮点数以覆盖 someFunc。像下面

    template <typename F, typename I>
    class B : B_Base<F, I>
    {
    }

    template <typename I>
    class B<float, I> : B_Base<flat, I>
    {
    public:
        void someFunc() {....}
    };

解决方案2.使用函数重载,将float作为输入或boost::is_same进行调度。不幸的是,你的函数someFunc没有参数。所以它需要改变界面。

于 2015-10-21T03:20:58.607 回答
0

我认为 C++ 专家 Mayer 为我们提供了一个优雅的功能。缺点是它取决于 GCC 功能。

#include <map>
#include <iostream>
#include <string>

using namespace std;


template<typename... T>
void TemplatePrint(T... args) {
    std::cout << __PRETTY_FUNCTION__ << std::endl;
}


int main()
{
    map<string, int> arr={{"1", 1}, {"2", 2}, {"3", 3}};
    auto itr = arr.find("3");
    TemplatePrint<decltype(itr)>(itr);


    return 0;
}

GCC 将打印出迭代器的真实 decltype(真的),即:

void TemplatePrint(T ...) [with T = {std::_Rb_tree_iterator<std::pair<const std::basic_string<char, std::char_traits<char>, std::allocator<char> >, int> >}]
于 2021-07-26T09:40:28.747 回答