【问题标题】:Problem with C++ Partial Template SpecializationC++ 部分模板专业化的问题
【发布时间】:2011-07-14 16:46:19
【问题描述】:

我有类似这样的情况:

template<class A, class B>
class MyClass<A, B>
{
  ...
  static A RARELY_USED_A;
}

// Seems to work but does not cover all possible cases, since 
// there may be instances of A that have no numeric limits.
template<class A, class B>
A MyClass<A, B>::RARELY_USED_A= std::numeric_limits<A>::max();

据我所见,这似乎可行。但是,在某些情况下,字符串可能会用作 A,所以我想我只需为这种特殊情况创建一个特化。

// Does not complile
template<class B>
string MyClass<string, B>::RARELY_USED_A= "";

不幸的是,这不符合错误消息:

error: template definition of non-template 'std::string MyClass<std::basic_string<char, std::char_traits<char>, std::allocator<char> >, B>::RARELY_USED_A'

请注意,另一方面,完整的专业化似乎可以工作(在运行时未经测试但可以编译)

// This complies but is not gernic enough and hence useless to me
template<>
string MyClass<string, string>::RARELY_USED_A= "";

我想,我一定是做错了什么。如果您能指出它到底是什么,我将不胜感激。我认为部分专业化应该以这种方式工作。

非常感谢。

e:将 DEFAULT_A 的名称编辑为 RARELY_USED_A,因为我认为“默认”在某种程度上具有误导性

【问题讨论】:

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


    【解决方案1】:

    使用继承来重用和专门化,而不复制所有通用代码:

    template<typename A>
    struct RarelyUsedShared
    {
        static A RARELY_USED_A;
    };
    
    template<typename A>
    A RarelyUsedShared<A>::RARELY_USED_A = std::numeric_limits<A>::max();
    
    template<>
    string RarelyUsedShared<string>::RARELY_USED_A = "";
    
    template<typename A, typename B>
    class MyClass<A, B> : RarelyUsedShared<A>
    {
      ...
    };
    

    请注意,这将导致在多个B 之间共享该成员,如果该成员应该是const 则可以。如果没有,帮助器可以采用两个模板参数,您可以对其进行部分特化:

    template<typename A, typename B>
    struct RarelyUsedNotShared
    {
        static A RARELY_USED_A;
    };
    
    template<typename A, typename B>
    A RarelyUsedNotShared<A, B>::RARELY_USED_A = std::numeric_limits<A>::max();
    
    template<typename B>
    struct RarelyUsedNotShared<string, B>
    {
        static A RARELY_USED_A;
    };
    
    typename<typename B>
    string RarelyUsedNotShared<string, B>::RARELY_USED_A = "";
    
    template<typename A, typename B>
    class MyClass<A, B> : RarelyUsedNotShared<A, B>
    {
      ...
    };
    

    【讨论】:

    • 谢谢。听起来不错。我仍然想知道为什么会有这种部分专业化的限制。但我想这个答案以一种优雅的方式解决了我的问题。
    • 现在我有另一个问题。由于 MyClass 是一种具有许多可能实例的容器类型,因此我无法将其拆分为 .h 和 .cpp 文件,而必须将整个内容放在头文件中。不幸的是,当从使用 MyClass 的多个对象链接二进制文件时,这样做会导致我对 RARELY_USED_A 的多个定义。
    • @b.buchhold:这完全是一个新问题,即使没有专业化你也会遇到这个问题,需要单独提问。而且,我想已经有人回答了,所以先搜索一下“模板静态多重定义”。
    【解决方案2】:

    您需要为整个班级提供部分专业化,而不仅仅是单个成员。

    【讨论】:

    • 嗯,这真的很烦人,因为它只不过是所有东西的重复代码,而不是一个成员。另外我想知道为什么只有这一个成员才能获得完整的专业化。
    • @b.buchhold:使用一个只有这个成员的助手类。然后,您可以在不重复代码的情况下对其进行专门化。你的主类可以继承它。
    • ...是的,这有点痛苦。请注意,在您的工作案例中,n.m.,您根本没有真正专门化该功能,而是为MyClassone 专用模板实例的一个成员提供定义。我想。
    • 是的,这是一种可怕、疯狂、荒谬的痛苦。
    【解决方案3】:

    如果你的RARELY_USED 是常量,你可以使用一个小助手类:

    template <class A, class B>
    const A MyClass<A, B>::RARELY_USED_A = Helper<A>::value;
    
    /*...*/
    
    #include <limits>
    #include <string>
    
    template <typename A> struct Helper { static const A RARELY_USED_A; };
    template <typename A> const A Helper<A>::RARELY_USED_A = std::numeric_limits<A>::max();
    
    template <> struct Helper<std::string> { static const std::string RARELY_USED_A; };
    const std::string Helper<std::string>::RARELY_USED_A = "";
    

    【讨论】:

    • 我不认为这可以编译,因为如果我没记错的话,静态/常量的东西既不能调用函数也不能初始化字符串。
    • 即使在 C++0x 中 max()constexpr?不过还没有测试过,所以这可能不起作用。
    • static 成员必须在类外定义,即使它们是在类内初始化的。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多