【问题标题】:Rules for implicit conversion of template arguments模板参数的隐式转换规则
【发布时间】:2012-04-05 15:21:03
【问题描述】:

如果您重载一个函数,然后使用与其中一个重载完全匹配的参数调用它

int f(int){return 3;}
int f(bool){return 4;}
...        //inside main()
f(1);      //Calls f(int)

编译器在尝试任何隐式转换之前简单地选择这个(完美)匹配。但是我一直在尝试重载函数 tempĺate,如

template <bool veracity>
int f(){return 1;}

template <int amount>
int f(){return 2;}

...        //inside main()
f<1>();

但编译器一直抱怨对重载 f() 的调用不明确,指出它可能是 f&lt;true&gt;()f&lt;1&gt;()。编译器不应该只选择完美匹配,而不是尝试将 1 转换为 true 吗?

我的印象是模板参数的隐式转换实际上比函数参数的隐式转换更具限制性。有没有办法解决这个问题?

【问题讨论】:

    标签: c++ templates overloading


    【解决方案1】:

    你提供的参数不是类型,它是一个值,所以规则有点不同——你需要对非类型参数应用规则。对于非类型参数,允许隐式转换。 §14.3.2/5:

    对用作非类型模板参数的每个表达式执行以下转换。如果一个非类型的模板参数不能被转换为相应模板参数的类型,那么程序是错误的。

    — 对于整数或枚举类型的非类型模板参数,应用转换后的常量表达式 (5.19) 中允许的转换。

    在 C++03 中,措辞略有不同,但效果基本相同(也是 §14.3.2/5):

    ——对于整数或枚举类型的非类型模板参数,应用整数提升 (4.5) 和整数转换 (4.7)。

    无论哪种方式,由于 1 既是 int 又可以隐式转换为 bool,所以您的调用是不明确的。

    【讨论】:

    • 我明白了。你知道这样的规则是否有特定的原因?我的意思是,是否存在一些技术困难或某些东西会使编译器无法将“精确匹配优先/隐式转换第二”逻辑(用于函数参数)应用于模板参数?
    • 不,我不确定。我的猜测是,这主要是因为规则已经很复杂,并且像重载那样添加一组“排名”规则会使它们更加复杂。我不确定,但我猜由于与模板的其他规则交互,排名规则最终也会与重载规则有一点不同,所以这不仅仅是说“候选函数将形成一个重载集,根据 §13.3 进行解析。”
    【解决方案2】:

    由于这不是编译器错误,而是语言功能(请参阅 this answer),因此您必须找到解决方法。

    要么你必须重命名你的函数,要么你可以使用这个 hack:

    template <typename T> struct F;
    
    template<> struct F<bool> {
      template <bool veracity>
      static int f(){return 1;}
    };
    
    template<> struct F<int> {
      template <int amount>
      static int f(){return 2;}
    };
    
    template <typename T, T value>
    int f() { return F<T>::template f<value>(); }
    
    // inside main():
    std::cout << f<int,  2>() << '\n'; // prints 2
    std::cout << f<bool, 2>() << '\n'; // prints 1
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-10-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多