首页 > 解决方案 > 主函数体未检测到对重载可变参数模板函数 C++ 的调用

问题描述

我目前正在学习可变参数模板函数和参数打包/解包。

这是我的代码,

template<typename T, typename U> 
void my_insert(std::vector<int>& v, T& t) {
    int i;
    if (typeid(t).name() == typeid(const char*).name()) {
        i = stoi(t);
    }
    else if (typeid(t).name() == typeid(char).name()) {
        i = t - 48;
    }
    else if (typeid(t).name() == typeid(int).name()) {
        i = t;
    }
    else if (typeid(t).name() == typeid(double).name()) {
        i = static_cast<int>(round(t));
    }
    else if (typeid(t).name() == typeid(bool).name()) {
        if (t) i == 1;
        else i == 0;
    }
    else if (typeid(t).name() == typeid(std::vector<U>).name()) {
        int j = 0;
        while (j < t.size()) {
            my_insert(v, t[j]);
            ++j;
        }
    }
    else return;
    v.push_back(i);
}
template<typename T, typename U, typename ...Args>
void my_insert(std::vector<int>& v, T& t, Args&... args) {
    int i;
    if (typeid(t).name() == typeid(const char*).name()) {
        if (isdigit(t[0])) i = stoi(t);
        // else do nothing
    }
    else if (typeid(t).name() == typeid(char).name()) {
        i = t - 48;
    }
    else if (typeid(t).name() == typeid(int).name()) {
        i = t;
    }
    else if (typeid(t).name() == typeid(double).name()) {
        i = static_cast<int>(round(t));
    }
    else if (typeid(t).name() == typeid(bool).name()) {
        if (t) i == 1;
        else i == 0;
    }
    else if (typeid(t).name() == typeid(std::vector<U>).name()) {
        int j = 0;
        while (j < t.size()) {
            my_insert(v, t[j]);
            ++j;
        }
    }
    //else do nothing
    v.push_back(i);
    my_insert(args...);
}

int main() {

    std::vector<int> v; 

    my_insert(v, "123", "-8", 32, 3.14159, true, true, false, '5', "12.3");

    return 0;
}

错误:没有重载函数 my_insert 的实例与参数列表匹配

print()我不明白我犯了什么错误,因为对我来说,a函数的完全相同的实现可以使用{ cout << t << endl; print(args...); },带签名<typename T, typename ...Args> void print(const T& t, const Args... args)

我知道可变参数函数可以通过递归调用同一函数的非可变参数重载版本来实现。所谓的基本案例陈述。

说了这么多,我不确定我做错了什么。

标签: c++visual-studiovariadic-functionspacking

解决方案


嗯......你的代码中有一些问题。

阻塞错误是模板参数U

template<typename T, typename U> 
void my_insert(std::vector<int>& v, T& t) 

template<typename T, typename U, typename ...Args>
void my_insert(std::vector<int>& v, T& t, Args&... args) 

编译器无法推断并调用函数

my_insert(v, "123", "-8", 32, 3.14159, true, true, false, '5', "12.3");

没有U解释

我想这个想法是“如果Tstd::vector某种类型U,则添加向量的所有元素”。如果我理解正确,我建议添加该函数的不同重载版本。

其他问题...

1)在几个点你写一些东西

    if (t) i == 1;  
    else i == 0;

在我看来,您使用运算符==(比较)而不是=(分配)。

一般建议:启用最高警告级别来拦截此类微不足道的错误。

2) 你的使用typeid

if (typeid(t).name() == typeid(char).name()) 

比较类型。

建议:std::is_same改用

if ( std::is_same<T, char>::value )

3)递归的基本情况是一个my_insert()与递归版本几乎相同的函数;唯一的区别是没有Args...参数和递归调用。

这很容易出错,因为如果您修改两个版本中的一个,您必须记住以相同的方式修改另一个。

建议:写一个空无一物的地面案例;某事作为

void my_insert (std::vector<int> & v)
 {  }

4)你不能编译

i = stoi(t);

什么时候t不是char const *

其他作业的类似问题。

问题是当你写[伪代码]

if ( condition )
   statement_1;
else
   statement_2;

编译器必须同时编译statement_1并且statement_2知道编译时间conditiontrueor false

为避免编译未使用的语句,您必须使用if constexpr.

所以你必须写一些东西

   if constexpr ( std::is_same_v<T, char const *> )
      i = std::stoi(t);
   else if constexpr ( std::is_same_v<T, char> )
      i = t - 48;
   else if constexpr ( std::is_same_v<T, int> )
      i = t;
   else if constexpr ( std::is_same_v<T, double> )
      i = static_cast<int>(std::round(t));
   else if constexpr ( std::is_same_v<T, bool> )
      i = t;

不幸的是,if constexpr仅从 C++17 开始可用。

在 C++17 之前,你必须编写不同的重载函数。

5)my_insert()递归调用,你要记住v向量

my_insert(args...); // <-- wrong! no v

my_insert(v, args...); // <-- correct 

6) 考虑"123"可转换为char const *但不是 a char const *(它是 a char const [4]) 的计数;所以,而不是

if constexpr ( std::is_same_v<T, char const *> )
   i = std::stoi(t);

你可以试试

if constexpr ( std::is_convertible_v<T, char const *> )
   i = std::stoi(t);

以下是您的代码的可能 C++17 实现

#include <cmath>
#include <string>
#include <vector>
#include <iostream>

void my_insert (std::vector<int> const &)
 { }

template <typename T, typename ... As>
void my_insert (std::vector<int> &, std::vector<T> const &, As const & ...);

template <typename T, typename ... As>
void my_insert (std::vector<int> & v, T const & t, As const & ... as)
 {
   int i{};

   if constexpr ( std::is_convertible_v<T, char const *> )
      i = std::stoi(t);
   else if constexpr ( std::is_same_v<T, char> )
      i = t - 48;
   else if constexpr ( std::is_same_v<T, int> )
      i = t;
   else if constexpr ( std::is_same_v<T, double> )
      i = static_cast<int>(std::round(t));
   else if constexpr ( std::is_same_v<T, bool> )
      i = t;
   // else ???

   v.push_back(i);

   my_insert(v, as...);
 }

template <typename T, typename ... As>
void my_insert (std::vector<int> & v, std::vector<T> const & t,
                As const & ... as)
 {
   for ( auto const & val : t )
      my_insert(v, val);

   my_insert(v, as...);
 }

int main ()
 {
   std::vector<int> v; 
   std::vector<char> u { '9', '8', '7' };

   my_insert(v, "123", "-8", 32, 3.14159, true, u, false, '5', "12.3");

   for ( auto const & val : v )
      std::cout << val << ' ';

   std::cout << std::endl;
 }

推荐阅读