如何使用模板根据数据类型调用函数?

时间:2019-04-15 23:07:45

标签: c++ arduino

我正在使用Arduino库,如果传递浮点数而不是整数值,则某些方法的行为将有所不同。之所以必须这样,是因为如果传递浮点数而不是整数,则基础函数必须执行更多的数学运算。

这里有一些孤立的,精简的代码来演示问题。

void printdata(uint32_t data) 
{
  Serial.printf("Printing unsigned integer %d", data);
}

void printdata(float data) 
{
  Serial.printf("Printing float %i", data);
}

template<typename Data>
void myTemplate(const Data& d)
{
  printdata(d);
}

如果传递整数(例如printdata(1000)),我希望模板函数调用printdata(uint32_t)。我还希望模板函数在传递浮点数(例如printdata(10.00))时调用printdata(float)。

但是,当我调用printdata(1000)时,编译器给我一个错误,提示call of overloaded 'printdata(const double&)' is ambiguous

能否无需手动投射所有内容来实现?我希望我正在编写的库对用户友好并且尽可能不冗长。手动投射所有内容对我来说并不是一个很好的解决方案。

谢谢!

2 个答案:

答案 0 :(得分:1)

考虑std::is_integral标头中的<type_traits>以及C ++ 17 constexpr if

std::is_integral会告诉您在编译时给定类型是否为整数类型。

constexpr if基本上是一个if语句,在编译时进行评估。未被执行的分支永远不会执行(实际上甚至不会被编译)。

#include <type_traits>

void printdata(uint32_t data)
{
    Serial.printf("Printing unsigned integer %d", data);
}

void printdata(float data)
{
    Serial.printf("Printing float %i", data);
}

template<typename Data>
void myTemplate(const Data& d)
{
    // uses C++17 constexpr if
    if constexpr (std::is_integral_v<Data>) printdata(static_cast<uint32_t>(d));
    else printdata(static_cast<float>(d));
}

编辑:但是,如果您不能使用C ++ 17,则需要使用更高级的模板逻辑,我将在下面进行演示。我还将避免使用type_traits标头中的任何内容,因为您提到由于某种原因您无权访问它?

注意:我将要展示的代码非常粗糙,我绝不建议在学术练习或好奇心之外编写代码。这样做的原因是缺少type_traits标头,这意味着我们必须定义的内容比我们以前要定义的要多得多。 SFINAE。此外,大多数模板代码都使用了大量type_traits的东西,这使它更加尴尬。

因此,在这一点上(没有type_traits标头或C ++ 17),我建议不要使用模板,而只是对要使用的每种类型进行重载 {{1 }},从而避免了模棱两可的重载问题。

printdata

答案 1 :(得分:0)

有时我们必须提供其他重载以消除选项之间的歧义。在这种情况下,我们将为printdata提供其他重载。

最好的选择是只为printdataint和您关心的其他数据类型添加其他double函数,但是如果可以,请使用{ {1}}和unsigned int s,您可以直接投放它们。

float