【问题标题】:How to make the compiler use the right template specialization?如何让编译器使用正确的模板特化?
【发布时间】:2011-05-19 15:37:51
【问题描述】:

考虑以下我的代码的简化版本。 我有一个模板类A,一个模板函数Fill,以及一个专门用于处理intchar 等基本类型的函数,还有另一个专门用于处理A

#include <sstream>
#include <string>
#include <iostream>

template<size_t C>
class A
{
public:
    A & operator=(std::string v) { 
        data[0] ='a';
        return *this; 
    }
    char data[C];
};

template<typename T> T Fill(std::string value, T default_value);

// Specialization for A<C>
template<size_t C>
A<C> Fill(std::string value, A<C> default_value) 
{
    if (value.empty())
        return default_value;
    A<C> result;
    result = value;
    return result;
}

// Specialization for int, double, char, etc
template<typename T>
T Fill(std::string value, T default_value)
{   
    if (value.empty())
        return default_value;

    T result;
    std::istringstream(value) >> result;
    return result;
}

void main()
{
    int abc = Fill(/*Get a string somehow*/"123", 0); // OK

    A<10> def;
    def = std::string("111");
    A<10> a;
    a = Fill(/*Get a string somehow*/"abc", def);     // OK
}

虽然我很惊讶编译器设法将参数与正确的模板特化相匹配,但效果很好。

问题出现在一些typedefs 上,它们简化了A&lt;x&gt; 的使用。这是一个简化的版本:

typedef A<12> A12;
...
A<12> def12;
def12 = std::string("12");

A12 a12;
a12 = Fill(/*Get a string somehow*/"xyz", def12);       // Not OK !

编译器没有检测到A12 类型实际上是A&lt;12&gt; 并使用了错误的函数特化,导致无法编译,因为 istringstream 无法将 operator&gt;&gt; 解析为A

我怎样才能使它使用正确的模板专业化?

【问题讨论】:

  • 第二个例子中的def是如何声明的?
  • 函数模板不能被部分特化(而且你也没有使用特化语法),所以在你的例子中你实际上是在重载。

标签: c++ templates template-specialization


【解决方案1】:

模板特化不是通过您将返回值分配到的位置来推断的。您必须显式实例化正确的版本:

a12 = Fill<A<12> >("xyz", def);

(或者你需要的任何东西......)

【讨论】:

  • 默认参数应该不够用吧?我想避免在调用地点指定类型。 +1 因为它可以工作!
  • @Gabriel:在你的例子中,default_valuedef,它的类型是A&lt;10&gt;,它与A&lt;12&gt; 不同! (除非我错过了什么。)
  • 除非可以从def 推断出类型,如果它与之前的def 相同,我认为应该是可能的......
  • @Gabriel:好的,在那种情况下,我不知道问题是什么!不过,我现在将留下我的答案......
  • 但是,如果def 的类型不是A&lt;12&gt;,那么这一行也不会编译。如果def 的类型 A&lt;12&gt;,则不需要显式实例化。
【解决方案2】:
typedef A<12> A12;
...
A12 a12;
a12 = Fill(/*Get a string somehow*/"xyz", def);       // Not OK !

在此示例中,您没有向我们显示def 的类型。假设和前面的例子一样,即A&lt;10&gt;,这样肯定会失败。

在您的模板中,第二个参数的类型必须与返回类型匹配。试试这个:

typedef A<12> A12;
...
A12 a12;
A12 def12;
a12 = Fill(/*Get a string somehow*/"xyz", def12);       // OK !

【讨论】:

    【解决方案3】:

    编译器没有检测到类型 A12 实际上是 A 并且使用了错误的函数特化

    实际上,由于您在示例中传递了A&lt;12&gt; def;(错误?),因此应该选择正确的重载(请参阅我对问题的评论)。您将结果分配给 A12 a; 这一事实不应影响重载解决方案。

    如果您的意思正好相反(传递 A12 并分配给任何东西),那么这可能是编译器缺陷。这可以正常工作here

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-01-30
      • 2010-11-19
      • 2012-04-20
      相关资源
      最近更新 更多