I am attempting to template a vector. In my main I have the following:
std::vector<Word> concordance = push_vector(data);
Where Word is a struct containing a std::string and an int, and data is a std::string. In my header file I have:
template <typename T>
std::vector<T> push_vector(std::string&);
However when I compile I get the following error:
main.cpp: In function ‘int main(int, char**)’:
main.cpp:27:53: error: no matching function for call to ‘push_vector(std::string&)’
main.cpp:27:53: note: candidate is:
templates.h:13:20: note: template<class T> std::vector<T> push_vector(std::string&)
I know I am missing something when I am implementing my template function, but I am not sure what. Thank you for your time in advance.
If I understand what you actually want to do perhaps something more like this:
template <typename T>
void push_vector(const std::string& str, std::vector<T>& vec)
{
// convert str to T if possible
// throw on failure maybe?
// assign vec with converted data
}
Then call it like so:
std::string data("Hello");
std::vector<Word> concordance;
push_vector(data, concordance);
Otherwise you would have to explicitly give the function it's template argument as it can't deduce from the rvalue you are assigning the return value into what the type should be. Not too mention passing an out paramater by reference like this saves you some performance.
Try:
std::vector<Word> concordance = push_vector<Word>(data);
The compiler can't resolve it without a hint because you don't use T anywhere other than the return value. Usually, the template parameter is also used as the type of one (or more) of the template functions' parameters, and then the compiler would be able to resolve it directly.
Related
I have a templated function where the only template parameter is used for passing a function pointer, and I want to be able to set a default argument (a specific function) to that parameter but it doesn't seem to work as I expected. Setting a default argument to the template parameter does not allow me to call the function with the defaulted argument omitted unless I make a separate overload instead. Is there a way to accomplish this using default arguments?
Here's what I tried at first, validator being the problematic parameter:
template <typename FuncT>
std::string ask_for(size_t arg_index, const std::string & prompt,
FuncT validator = Validators::is_not_empty, // default does not work!
std::ostream & os = std::cout);
(Validators is a namespace containing helper functions intended to pass to this function.)
The last parameter os does react to the default argument as I expected; ask_for(0, Validators::does_file_exist) works with os being set to std::cout.
But if I call ask_for(1) it does not call ask_for(1, Validators::is_not_empty) as I expected, instead it gives me this error trace:
error: no matching function for call to 'ask_for(int, const char [64])'
note: candidate: 'template<class FuncT> std::string ask_for(size_t, const std::string&, FuncT, std::ostream&)'
note: template argument deduction/substitution failed:
note: couldn't deduce template parameter 'FuncT'
Shouldn't it be able to deduce the template parameter by the given default argument? Or am I misunderstanding how default arguments are implemented for template parameters?
However, I was able to get the expected behavior by writing a separate overload and calling it instead:
template <typename FuncT>
std::string ask_for(size_t arg_index, const std::string & prompt,
FuncT validator, // no default here...
std::ostream & os = std::cout);
// ...overloaded version calls function with desired default argument
std::string ask_for(size_t arg_index, const std::string & prompt)
{
return ask_for(arg_index, prompt, Validators::is_not_empty);
}
Is there a way to set a default argument for the templated parameter to a function pointer, or must I create a separate overload to achieve this? Would this be possible with a template specialization or if I remove the template parameter altogether and use a specific function pointer instead?
I would like the default argument notation for readability, but I am mostly interested in efficiency.
Default argument cannot be used to deduce a template argument, but you can also default FuncT.
template <typename FuncT = decltype(&Validators::is_not_empty)>
std::string ask_for(size_t arg_index,
const std::string & prompt,
FuncT validator = &Validators::is_not_empty,
std::ostream & os = std::cout);
void test(const std::size_t& x) {
std::array<std::string, x> arr;
}
When I compile the above code I get this error.
main.cpp: In function ‘void test(std::size_t&)’:
main.cpp:15:24: error: ‘x’ is not a constant expression
How can I get the above code to compile?
Template arguments must always be constant expressions, and function parameters are never constant expressions. To make this code work, you could do as is suggested in the comments and use std::vector instead, or you could make your test function be a template and make x be a template parameter instead of a function parameter.
I use boost::any, and have some function which retrieves such a value, but may fail, so it actually returns std::optional<boost::any> (well, for now it's std::experimental::optional). Now, without the optional, I get my typed value back using boost::any_cast(my_retrieved_any). To handle the optional case, I've written the following:
template<typename ValueType>
inline const optional<ValueType> boost_any_cast(const optional<boost::any>& operand)
{
return operand ? boost::any_cast(operand.value()) : nullopt;
}
But this doesn't compile (with Boost 1.58 and GCC 4.9.3). I get:
/file.cpp(12): error: no instance of overloaded function "boost::any_cast"
matches the argument list
argument types are: (const boost::any)
How is this possible? Why is the argument not boost::any& ? I tried setting a variable to operand.value(), then passing that to the any_cast - but that didn't seem to help either:
template<typename ValueType>
inline const optional<ValueType> boost_any_cast(const optional<boost::any>& operand)
{
if (operand) {
boost::any x(operand.value());
return boost::any_cast(x);
}
return nullopt;
}
This gets me:
/file.cpp(13): error: no instance of overloaded function "boost::any_cast"
matches the argument list
argument types are: (boost::any)
There must be something I'm not taking into account regarding boost::any's... what is it? And how can I fix this "casting" operation?
The boost::any_cast requires a template argument;
template<typename T> T any_cast(const any &);
From you code snippet, you probably need;
boost::any_cast<ValueType>(operand.value())
I have a function template that extracts data from an image and copies it to a smaller array (which I call a Patch) the template function is called copyPatch. It is defined as:
template <class DestType, class SrcType, class Transformation>
bool copyPatch(Patch<DestType> &patch,
ImageData<SrcType>* src_data,
size_t src_ul_pix,
size_t src_ul_line)
Note: the Transformation parameter allows me to pass in a class that performs some transformation on the data. I call the template function as follows,
copyPatch<float, uint8_t, StraightCopy>(m_patch_data, m_data.t8u,
ul_pix, ul_line)
where m_patch_data is of type Patch<float> and m_data.t8u is a member of a union defined as follows:
union {
ImageData<uint8_t>* t8u;
ImageData<uint16_t>* t16u;
ImageData<int16_t>* t16s;
ImageData<uint32_t>* t32u;
ImageData<int32_t>* t32s;
// A bunch more of these
void* tvoid;
} m_data;
When I compile this I get the following error (that I've doctored a bit):
error: no matching function for call to:
copyPatch(Patch<float>&, ImageData<unsigned char>*&, size_t&, size_t&)’
copyPatch<float, uint8_t, StraightCopy>( m_patch_data, m_data.t8u, ul_pix, ul_line);
^
note: candidate is:
template<class DestType, class SrcType, class Transformation>
bool copyPatch(Patch<T>&, ImageData<SrcType>*, size_t, size_t)
template argument deduction/substitution failed:
To me, I don't see why the function didn't match. The only possible reason I can see is that for the 2nd parameter it wants a pointer (which is what I thought I was passing), but the calling code seems to be passing a reference to a pointer.
Compiler is g++ 4.8.1.
As pointed out in the comments the problem possibly with my Transformation (StraightCopy) which is defined as follows:
template<class Dest, class Src>
class StraightCopy {
public:
Dest operator()(Src s) { return static_cast<Dest>(s); }
};
I missed passing the parameters to my StraightCopy class.
Thanks to PlasmaHH for pointing me in the right direction. My transformation type (StraightCopy) needed parameters. So my call looks like:
copyPatch<float, uint8_t, StraightCopy< float, uint8_t > >( m_patch_data, m_data.t8u, ul_pix, ul_line);
Isn't that beautiful :o)
I have been playing around with variadic templates in the new c++ standard and came up with a map function (headers + using decs excluded):
template<typename T>
T square(T i)
{
return i * i;
}
template <typename T, typename... Ts>
const tuple<Ts...> map(const T f, const Ts...args)
{
return make_tuple(f(args)...);
}
int main(int c, char *argv[])
{
tuple<int, int> t;
int (*fp) (int) = square;
t = map(fp, 6, 8);
cout <<get<0>(t) <<endl;
cout <<get<1>(t) <<endl;
return 0;
}
Which works. As long as all the arguments are the same type for map. If I change the main to use a slightly more general form:
tuple<int, float> t;
t = map(square, 6, 8.0f);
gcc 4.4 reports:
In function ‘int main(int, char**)’:
error: no matching function for call to ‘map(<unresolved overloaded function type>, int, float)’
Any ideas how to make this work?
First, you can't pass around an unresolved function template as a pointer (or template parameter), you can only pass around instances of it. What that means is that your template's first argument is being passed as an int (*)(int) in this example, and it cannot call the float (*)(float) instantiation. I'm not sure of the best way to fix that, but anyway it's not technically what you asked about.
I don't have a compiler to test this on, but I think if you use std::function to infer the types that the function you are passing in wants, you might be able to cast the parameters to the function. Like this:
template<typename T, typename Ts...>
tuple<Ts...> map(std::function<T (T)> const &f, Ts... args) {
return make_tuple(static_cast<Ts>(f(static_cast<T>(args)))...);
}
See, I think you need to cast both the parameter (as a T) and the return type (as a Ts) for the function since it seems some implicit conversion rules are not working inside this template.
If my syntax doesn't work (it probably doesn't, the ...s are tricky when you don't have a compiler for them), it might be possible that you could rewrite this as a much more verbose function which unpacks each Ts before calling the function, and then builds up a tuple as it goes. I'm not sure if that is really necessary, but my feeling is that compiler support for all of the ... unpacking is a little spotty right now, so even if you come up with something that should work, I wouldn't be surprised if your compiler couldn't handle it.