Search code examples
c++variadic-templates

Compiling a function with templates fails in variadic template function


I have come across a compiler error involving variadic templates. The following code is a strongly simplified version which reproduces the error in my original code:

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

typedef std::vector<std::string> stringvec;

// dummy function: return string version of first vectorelemenr
template<typename T>
std::string vecDummy(const std::string sFormat, const T t) {
    std::stringstream ss("");
    if (t.size() > 0) {
        ss << t[0];
    }
    return  ss.str();    
}

// recursion termination
std::string recursiveY(stringvec &vFlags,  uint i) {
    return "";
}  

// walk through arguments
template<typename T, typename... Args>
std::string recursiveY(stringvec &vFlags,  uint i, T value, Args... args) {

    std::string sRes = "";
    if (vFlags[i] == "%v") {
        sRes += vecDummy(vFlags[i], value);
    }    
    sRes += " "+recursiveY(vFlags, i+1, args...);

    return sRes;
}

int main(void) {
    stringvec vPasta   = {"spagis", "nudle", "penne", "tortellini"};
    stringvec vFormats = {"%v", "%s"};

    std::string st = "";
    st += recursiveY(vFormats, 0, vPasta, "test12");
    std::cout << ">>" << st  << "<<" << std::endl;

    return 0;
} 

This simple code should walk through the arguments passed to recursiveY() and, if the current format string is "%v" it would pass the corresponding argument to vecDummy() which would return a string version of the vector's first element (if there is one).

The error message from the compiler is

sptest2.cpp: In instantiation of ‘std::string vecDummy(std::string, T) [with T = const char*; std::string = std::__cxx11::basic_string<char>]’:
sptest2.cpp:30:25:   required from ‘std::string recursiveY(stringvec&, uint, T, Args ...) [with T = const char*; Args = {}; std::string = std::__cxx11::basic_string<char>; stringvec = std::vector<std::__cxx11::basic_string<char> >; uint = unsigned int]’
sptest2.cpp:32:27:   required from ‘std::string recursiveY(stringvec&, uint, T, Args ...) [with T = std::vector<std::__cxx11::basic_string<char> >; Args = {const char*}; std::string = std::__cxx11::basic_string<char>; stringvec = std::vector<std::__cxx11::basic_string<char> >; uint = unsigned int]’
sptest2.cpp:43:21:   required from here
sptest2.cpp:12:11: error: request for member ‘size’ in ‘t’, which is of non-class type ‘const char* const’
   12 |     if (t.size() > 0) {
      |         ~~^~~~

It seems as if the compiler uses all types i pass to recursiveY() in main, but vecDummy() is designed to only work with vectors of some kind (and not with const char*, for example).

Is there a possibility to modify this code so that it will work as intended?

Is there perhaps a way of assuring the compiler that i will only pass vectors to vecDummy() (even at the risk of a runtime error or unexpected behaviour - similar to passing an integer to printf() when it expects a string)?


Solution

  • You can add an overload of vecDummy that handles the std::vector case and 'dumb down' the more general one to (say) just return an empty string:

    // dummy function: return string version of first vectorelement (catch-all)
    template<typename T>
    std::string vecDummy(const std::string, const T) {
        return "";
    }
    
    // dummy function: return string version of first vectorelement (vectors only)
    template<typename T>
    std::string vecDummy(const std::string, const std::vector <T> &t) {
        std::stringstream ss("");
        if (t.size() > 0) {
            ss << t[0];
        }
        return  ss.str();    
    }
    

    Live demo