1

So what I am trying to do is write a generic function that takes in a string a splits it into a typed vector. Here is my code, and the issue is that it can't resolve the stod function type to the generic function wrapper I specified.

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

using std::vector;
using std::string;
using std::function;
using std::stringstream;


int main(int argc, const char * argv[]) {
    SplitStringToTypedVector("1.23 3.45 5.21", ' ', static_cast<double (*)(const string&, size_t*)>(&std::stod)); 

    system("pause");
    return 0;
}

template <typename T>
vector<T> SplitStringToTypedVector(const string &s, char delim, function<T (*)(const string&, size_t*)> conversionFunc) {
    vector<T> elements;
    stringstream stream;
    string element;
    while (getline(stream, element, delim)) {
        elements.push_back(conversionFunc(element));
    }
    return elements;
}
user1634494
  • 609
  • 1
  • 7
  • 23

2 Answers2

0

Probably cleaner to use a lambda to resolve the function type, rather than worry about disambiguating the overloads of stod:

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

using std::vector;
using std::string;
using std::function;
using std::stringstream;

template <class Func>
auto SplitStringToTypedVector(const string &s, 
                                   char delim, 
                                   Func&& conversionFunc) {
  using result_type = decltype(conversionFunc(s));
    vector<result_type> elements;
    stringstream stream;
    string element;
    while (getline(stream, element, delim)) {
        elements.push_back(conversionFunc(element));
    }
    return elements;
}

int main(int argc, const char * argv[]) {
    SplitStringToTypedVector("1.23 3.45 5.21", 
                             ' ', 
                             [](std::string const& s) { return std::stod(s); }); 

    system("pause");
    return 0;
}
Richard Hodges
  • 68,278
  • 7
  • 90
  • 142
  • Question marked `C++11`, `auto` return type with no trailing type entered the game with C++14. So this answer doesn't apply to the question as it is. At least, mention it. – skypjack Sep 10 '16 at 21:48
  • does anyone still use c++11? It can be fixed with std::result_of. – Richard Hodges Sep 10 '16 at 21:50
  • You know, the answer is yes: unfortunately there exists also someone that still uses C++98 out there. :-( – skypjack Sep 10 '16 at 21:54
  • History teaches that clinging to the past is a failed strategy. I am strongly of the view that compilers should default to the very latest standard. – Richard Hodges Sep 10 '16 at 21:56
  • So true, but this doesn't change the facts: there exists someone that still uses older revision of the language. I know, it's something we must learn to deal with... :-) – skypjack Sep 10 '16 at 22:05
  • 1
    Does this mean that you want to put this answer on a question about **? After all, does anyone use that hated language? Please teach me the meaning in this. – Johannes Schaub - litb Sep 10 '16 at 22:06
  • BTW, the omission of the return type is fine, it's in C++11. The `auto` parameter is not, and it cannot be fixed with `std::result_of` :) – Johannes Schaub - litb Sep 10 '16 at 22:11
  • Fixed. As for c++11, if you have a c++11 compiler and you have kept it up to date, then you have a c++14 compiler. There is no need to regress. Some architectures only have a c++98 compiler available for them, because the architectures themselves are anachronistic. But nothing went out of date between c++11 and c++14. There's no excuse. – Richard Hodges Sep 10 '16 at 22:16
  • @RichardHodges "History teaches that clinging to the past is a failed strategy." Obstinately clinging to the past, yes. Attempting a thing in the "old fashion" way?... mmm... may be a great way to learn why the new things are better (and perhaps what price one has to pay for that better) and *why* that better came to be. (yes, this may have nothing to do with the problem at hand, just a reaction to "forget the old, is inexcusable to even think using it") – Adrian Colomitchi Sep 11 '16 at 02:41
  • Let's be honest though, c++14 was merely a bug fix on c++11. If you have a bug fix available, why wouldn't you use it? Since no processors were decommissioned in gcc, clang, msvc, etc between c++11 and c++14, there seems to me to be no reasonable argument for keeping ones codebase confined to c++11, and no valid reason for refusing to update ones toolset (which is costless, both in terms of compatibility and money) – Richard Hodges Sep 11 '16 at 07:57
0

Just some points about your code.

(1) you call SplitStringToTypedVector(), in main(), before it's definition. That's bad. You should swith main() and , SplitStringToTypedVector() or add a prototipe of SplitStringToTypedVector() before main()

(2) using std::function you have to avoid (*); so

function<T(const string&, size_t*)> conversionFunc

instead of

function<T(*)(const string&, size_t*)> conversionFunc

(3) your function conversionFunc() is declared receiving 2 arguments. I know that the second argument of std::tod has a default value but I don't think that SplitStringToTypedVector() could able to know it. So is wrong calling conversionFunc() with an argument

elements.push_back(conversionFunc(element));

You have to call it with two

elements.push_back(conversionFunc(element));

(4) I don't know how to force the recognition of type T calling SplitStringToTypedVector() (my limit, I suppose); but you can explicit it

SplitStringToTypedVector<double>("1.23 3.45 5.21", ' ', static_cast<double (*)(const string&, size_t*)>(&std::stod));
max66
  • 65,235
  • 10
  • 71
  • 111