【问题标题】:Overloading based on non-type template parameter基于非类型模板参数的重载
【发布时间】:2016-01-24 05:46:18
【问题描述】:

我们熟悉基于函数参数的重载。但是为什么我们不能基于非类型模板参数进行重载呢?通过这样的重载,您不必为了重载目的而添加额外的函数参数,这可能会对运行时性能产生负面影响。唉,下面的代码无法编译:

template <bool>
void func() {}

template <int>
void func() {}

int main() {
  func<0>();
}

产生的错误信息是

error: call of overloaded 'func()' is ambiguous
       func<0>();
               ^
note: candidate: void func() [with bool <anonymous> = false]
     void func() {}
          ^
note: candidate: void func() [with int <anonymous> = 0]
     void func() {}
          ^

请注意,这可能比

更有效
void func(bool) {}

void func(int) {}

允许这种用法有什么问题吗?

【问题讨论】:

  • 它在 VS 2013 中对我来说编译得很好。但如果我尝试实际调用其中一个,它会说它是模棱两可的。如果我将int 替换为std::ostream&amp;,那么它就可以正常工作。不过,可能是特定于 VS 的。
  • 你有exact usage scenario (MCVE)吗?如果您不实例化模板,它不会生成任何代码。那么,你如何实例化它们呢?另外,你如何调用那些重载的函数(在第二个 sn-p 中)?
  • @SergeyTachenov MCVE 中的“C”已经完成。我确信可以创建一个 MCVE。
  • 你可以声明它们;你不能真正使用bool 一个,因为模板参数没有迷你重载分辨率;模板参数类型的有效转换常量表达式的所有内容都同样好。无论如何,如果您确实看到传递给控制重载解决方案的虚拟参数的负面影响,您应该向编译器供应商提交错误,而不是扭曲您的代码(进一步)。
  • 如果调用 func(bool) 与 func&lt;true&gt;() 对您的应用程序的性能产生影响,我会说您的状态非常好。

标签: c++ templates overloading language-lawyer


【解决方案1】:

如果您愿意接受一些添加的语法,您可以使用:

// No default implementation.
template <typename T, T value> struct Impl;

// Implement the bool/true version
template <> struct Impl<bool, true>
{
   void operator()() {}
};

// Implement the bool/false version
template <> struct Impl<bool, false>
{
   void operator()() {}
};

// Implement the int version
template <int N> struct Impl<int, N>
{
   void operator()() {}
};

template <typename T, T value>
void func()
{
   Impl<T, value>()();
};

int main()
{
   func<bool, true>();
   func<int, 10>();
}

免责声明

我不知道这是否会比调用func(true) 更好。

【讨论】:

  • 天啊,你正在创建一个空对象!它“可能对运行时性能产生负面影响”!! (+1,顺便说一句,虽然我个人更喜欢将其设为静态成员函数。)
  • @T.C.我感到惭愧。看来我太关注无关紧要的琐碎事情了。
【解决方案2】:

Andrei Alexandrescu 在 IIUC 的“现代 C++ 设计”中写到了这个,看起来 std::integral_constant 基本上可以给出你想要的效果,不是吗?与以下内容相比,主要改进是什么?它基本上允许重载(至少是整数类型的)常量。

#include <type_traits>


using tt = std::integral_constant<bool, true>;
constexpr tt t;
using ft = std::integral_constant<bool, false>;
constexpr ft f;


void func(tt) {};

void func(ft) {};


int main()
{
    func(t);
    return 0;
}

【讨论】:

  • 在我的例子中,两个重载都接受func&lt;0&gt;(),除了一个比另一个更匹配。在你的情况下,这不成立。这确实对我的用例产生了影响。
  • @Lingxi 这也许是你心目中的更好匹配。不在标准中。
  • @Lingxi 我想知道这一点。 IIUC,您的问题的标题和正文之间存在细微差异。我回答了标题。我相信 T.C. 的评论针对的是身体。
【解决方案3】:

你为什么要这样做?

模板是为不同类型的函数行为相似的情况设计的(例如找到最大值,只要该类型支持运算符'>',您就可以找到最大值。不管是 int 还是 float 等)。

你应该只是超载而不用担心影响,它没有你想象的那么糟糕。如果函数之间的行为足够不同,则不必费心使用模板

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-03-18
    相关资源
    最近更新 更多