Given this code:
#include <string>
#include <vector>
#include <iostream>
template <typename T>
std::string stringify(const T&) {
return "{?}";
}
template <typename T>
std::string proxy(const T& in) {
return stringify(in);
}
// trying to specialize "stringify()"
template <typename T>
std::string stringify(const std::vector<T>& in) {
return "vector specialization!";
}
template <>
std::string stringify(const std::vector<int>& in) {
return "INT vector specialization!";
}
int main() {
std::cout << proxy(1); // calls the 1st
std::vector<int> intVec;
std::cout << proxy(intVec); // calls the 1st
std::vector<double> dblVec;
std::cout << proxy(dblVec); // calls the 1st
return 0;
}
How can I specialize stringify() for vector<> after proxy<>?
Currently I get {?}{?}{?}
If I delete this one - stringify(const std::vector<T>& in) then the vector<int> starts getting called because it would be a specialization of the first.
Then I would get {?}INT vector specialization!{?}
Is there any way to call any of the 2 vector specialization stringification functions from proxy() - if they are defined last - after the proxy() function?
Is there a way to partially specialize on vector<> and still get called from proxy<>?
I don't want to specialize for vector<int>, vector<double>, vector<UserType>...
EDIT: forgot to mention I need this for C++98
First of all, avoid specializing function templates, prefer overloading. See Herb Sutter's article on the potential pitfalls.
Secondly, the issue you're running into involves how name lookup works for dependent names in function templates. Inside proxy<T>, stringify is a dependent name - it depends on T. That name will be looked up at the point of definition of the template (which will find stringify<T>(const T&) and not the other overload) and again at the point of instantiation in the associated namespace of the arguments (which would be std). Neither of those lookups find your other functions.
It's that second part of lookup - the argument-dependent lookup - that we can take advantage of. Let's just stick everything in one namespace (which I'm naming N arbitrarily, feel free to rename as appropriate):
namespace N {
struct helper { };
template <typename T>
std::string stringify(helper, const T&) {
return "{?}";
}
}
template <typename T>
std::string proxy(const T& in) {
return stringify(N::helper(), in);
}
Ok, so far we've changed absolutely nothing. We still get {?} in all cases. But the now we can stick further overloads (not specializations) of stringify still in that namespace but after the definition of proxy:
namespace N {
template <typename T>
std::string stringify(helper, const std::vector<T>& ) {
return "vector overload!";
}
std::string stringify(helper, const std::vector<int>& ) {
return "INT vector overload!";
}
}
Those two overloads will be found by the second phase of the name lookup because N is an associated namespace of helper. Now proxy(intVFec) will find all three overloads of stringify instead of just the one. And now your code prints:
{?}INT vector overload!vector overload!
as desired. None of the above requires C++11.
Related
I'm writing an extensible library where it has become convenient to overload STL's to_string() for custom types. For that I've designed a generic overload template that throws an exception if not specialized:
namespace std {
// ...
template < typename T >
inline std::string to_string(const T& in, const std::string& separator = ",") {
throw std::runtime_error("invalid call to " + std::string(__func__) + "(): missing template specialization for type " + typeid(T).name());
}
} // namespace std
This is useful mainly because the description will provide a clear explanation on the issue and how to solve it, and avoids having to use polymorphism to implement derived implementations (the function is only marginally/optionally required for certain applications such as serialization, I/O, etc.).
However, the issue with this approach is that the overload template will be deduced even with types where <string> already provides an overload for.
My question is if is there a way to force the non-template overload to be used only when there is no non-template definition available?
I recommend that you do not generate a runtime exception for something that should be a compilation failure.
It could look like this:
#include <string>
#include <type_traits>
namespace extra {
template <class T>
inline std::string to_string(const T& in) {
static_assert(std::is_arithmetic_v<T>, "T needs extra::to_string overload");
return std::to_string(in);
}
} // namespace extra
... and then you don't need to check if it's an arithmetic type at the call site:
template <class T>
void func(const T& arg) {
std::cout << extra::to_string(arg);
}
Demo
I ended up declaring to_string on a different namespace, and made use of type traits to delegate basic types towards STL's std::to_string:
namespace extra {
template < typename T >
struct invalid : std::false_type { /* ... */ };
template < typename T >
inline std::string to_string(const T& in) {
// static_assert(invalid< iT >::value, "Invalid call to extra::to_string(): missing template specialization for required type!"); // never compiles
throw std::runtime_error("Invalid call to extra::_to_string(): missing template specialization for required types[" + std::string(typeid(T).name()) + "]!");
}
} // namespace extra
template < typename T >
void func(const T& arg) {
// ...
if constexpr (std::is_arithmetic< T >()) {
std::cout << std::to_string(arg);
} else {
std::cout << extra::to_string(arg);
}
// ...
}
Although I am still trying to figure out how to proper write the static assertion in order to generate the error during compilation, at this stage this behaves how I needed it to.
Its simplified version of my real problem. Why in the first case template specialization doesn't work?
If I swap first two functions then it will work.
Strange, but it works with msvc 19...
#include <string>
#include <vector>
#include <iostream>
template<typename T, typename M>
void write_impl(T &result, M m) {
for (const auto &i : result) {
write_impl(i, m);
}
}
template<typename M>
void write_impl(const std::string &result, M m) {
std::cout << result;
}
template<typename T>
void write_impl_1(T &result) {
for (const auto &i : result) {
write_impl_1(i);
}
}
template<>
void write_impl_1(const std::string &result) {
std::cout << result;
}
int main() {
std::vector<std::string> a{"42", "43", "44"};
write_impl(a, 42); // compile time error
write_impl_1(a); // works fine
}
Godbolt link
The first case isn't a case of template specialization; it's function overloading.
Doesn't works because the first function call the second one that isn't declared. Switching the order, as you can see, works because the first (now second) know the declaration (and the definition too) of the second (now first).
You can't have template partial specialization for functions in C++; only full specialization.
You really need a sort of partial specialization, you can pass through a class/struct and a function inside it. You can partially specialize the struct/class.
For example
#include <string>
#include <vector>
#include <iostream>
template <typename T, typename M>
struct foo
{
static void bar (T & result, M m)
{
for (const auto &i : result)
foo<decltype(i), M>::bar(i, m);
}
};
template <typename M>
struct foo<std::string const &, M>
{
static void bar (std::string const & result, M)
{ std::cout << result; }
};
int main()
{
std::vector<std::string> a{"42", "43", "44"};
foo<decltype(a), int>::bar(a, 42);
}
But, as you can see, isn't really handy.
Obviously, if you don't need a partial-specialization-for-function emulation, and you are comfortable with different and overloaded template function (given that are calling each other) you can declare the first, declare and define the second and define the first;
Something as
template <typename M>
void write_impl (std::string const &, M);
template<typename T, typename M>
void write_impl (T & result, M m)
{
for (const auto &i : result)
write_impl(i, m);
}
template <typename M>
void write_impl (std::string const & result, M m)
{ std::cout << result; }
First, interesting find! Took me a moment.
Second, there is no such thing as partial specialization of function template.
Full specialization is OK, so the second implementation will chose the specialization.
The first case is an overload resolution between two template functions, the more specialized will be chosen. The compiler will first construct the overload list - with candidates for the call.
Here's the thing, void write_impl(const std::string &result, M m) won't be considered because it is not defined yet! The point of instantiation is directly after the template's definition. So, only the first template is in the overload set, it will match because a string is iterable and the instantiation will fail because char is not.
This will raise the same error about foo:
#include <string>
#include <vector>
#include <iostream>
template<typename T>
void bar(T &result) {
foo();
}
void foo(){}
int main() {
std::vector<std::string> a{"42", "43", "44"};
bar(a);
}
Why does the second case work then? Because the compiler will "look ahead" to see all possible specializations. But they still have to be present at the point which would instantiate the specialization. So, my belief here is that the second case is undefined behaviour, based on this answer. I am not very well versed in this dark corner of C++, I might be wrong here.
Why does MSCV work? Beats me, it is sometimes "special", maybe their point of instantiation is wrong, foo will incorrectly work too.
I want all my saving and loading of data to go through the same functions to reduce the chance of bugs. To do this I used a lot of templates (and much function overloading). It worked, my code is now much cleaner, but I was unable to use const for saving (because it goes through the same functions as the loader does, where the data is kept non-const).
I'd like to use the const correctly, so here is an attempt to get a simple version working, where the data (in this case std::vector) is non-const for std::ifstream, and const otherwise:
#include <iostream>
#include <fstream>
#include <vector>
template <class Foo>
void Overload(const Foo & foo)
{
std::cout << "went to const" << std::endl;
}
template <class Foo>
void Overload(Foo & foo)
{
std::cout << "went to non-const" << std::endl;
}
template <class StreamType, typename... Arguments>
void ReadOrWrite (
/* for 1st argument */ StreamType & filestream,
/* type for 2nd argument */ typename std::conditional<
/* if */ std::is_same<StreamType, std::ifstream>::value,
/* then */ std::vector<Arguments...>,
/* else */ const std::vector <Arguments...>
>::type
/*2nd argument name */ & vector
)
{
Overload(vector);
}
int main ()
{
std::ofstream output_filestream;
std::ifstream intput_filestream;
std::vector<int> vector;
ReadOrWrite(output_filestream, vector);
ReadOrWrite(intput_filestream, vector);
return 0;
}
I know that it will compile/run properly if I edit the function calls to this:
ReadOrWrite<std::ofstream, int>(output_filestream, vector);
ReadOrWrite<std::ifstream, int>(intput_filestream, vector);
But I don't want the user of the function to need to list the types during the function call.
Is there a clean way to do what I'm suggesting?
EDIT
There appears to be a question over the legitimacy of my motive.
I did not explain my motive thoroughly because it's not overly simple (neither is it overly complicated) and I respect the readers' time.
The example I gave was the bare component of what I haven't been able to solve - and the "overload" functions were just included to see if it worked.
However it appears that my lack of explanation has caused confusion, so I will expound:
I have made a small library to handle the general-case saving and loading of data. It successfully allows the users' classes to have simple save/load methods by using the following interface:
class SomeClass
{
public:
template <class StreamType>
void SaveOrLoad(StreamType & filestream)
{
saveload::SaveToOrLoadFromFile(filestream,
data_1_,
data_2_,
/* ..., */
data_n_,
);
}
void SaveToFile (const std::string & filename)
{
std::ofstream output_filestream(filename, std::ios::binary);
// file handling
SaveOrLoad(output_filestream);
}
void LoadFromFile (const std::string & filename)
{
std::ifstream input_filestream(ptf::problem_input_file, std::ios::binary);
// file handling
SaveOrLoad(input_filestream);
}
};
This library handles all fundamental data types, STL containers, and any other containers which use the correct SaveOrLoad(StreamType &) interface, including saving and resizing of all containers. The library has forced all saves and loads to go through the same deterministic functions, and hence has completely removed the potential for bugs involving of a save/load mismatch (unless the user misuses the library's simple interface).
The problem that I have with my library - and hence the reason for my question - is a theoretical one because I have no need for it presently: The SaveToFile method should be able to be const.
The best suggestion would be to provide two separated functions, since reading and writing are two distinct operations, no matter what type you sent in it. For example, someone could be fstream for both input and output. Simply by the type system, you can't know the intent. The decision of reading or writing is usually an intent, and these are rarely embeddable into the type system.
Since saving and loading are distinct operation, it should be distinct functions (possibly sharing code between them)
If you really want a function that do both and switch between the types, then I'd suggest constrain the functions for input or output:
// output streams
template <class StreamType, typename... Arguments,
typename std::enable_if<std::is_base_of<std::ostream, StreamType>::value, int>::type = 0
>
void ReadOrWrite (
StreamType & filestream,
std::vector<Arguments...> const& vector
) {
Overload(vector);
}
// input streams
template <class StreamType, typename... Arguments,
typename std::enable_if<std::is_base_of<std::istream, StreamType>::value, int>::type = 0
>
void ReadOrWrite (
StreamType& inputstream,
std::vector<Arguments...>& vector
) {
Overload(vector);
}
Since the second is more specialized than the first, it will be taken whenever the stream is std::istream and the vector is mutable. Otherwise, the first one is taken.
Live example
Another overload solution could transform ReadOrWrite(), almost as you have written in your question, in an helper function
template <typename ... Args, typename ST>
void ReadOrWrite_helper (ST &, typename std::conditional<
std::is_same<ST, std::ifstream>::value,
std::vector<Args...>,
std::vector<Args...> const>::type vec)
{ Overload(vec); }
adding a overloaded couple of ReadOrWrite() function to select select the Args... and explicit them calling the helper function
template <typename ... Ts>
void ReadOrWrite (std::ifstream & is, std::vector<Ts...> & vec)
{ ReadOrWrite_helper<Ts...>(is, vec); }
template <typename ... Ts>
void ReadOrWrite (std::ofstream & is, std::vector<Ts...> const & vec)
{ ReadOrWrite_helper<Ts...>(is, vec); }
Observe that, given that the Args... types are in non deduced context so are to explicated, I've placed they, in the ReadOnWrite_helper() template parameter declaration, before ST; so there is no need to explicit also ST.
Observe also that if you don't need to know the Args... types inside ReadOrWrite_helper(), all became simpler
template <typename V, typename ST>
void ReadOrWrite_helper (ST &, V & vec)
{ Overload(vec); }
template <typename V>
void ReadOrWrite (std::ifstream & is, V & vec)
{ ReadOrWrite_helper(is, vec); }
template <typename V>
void ReadOrWrite (std::ofstream & is, V const & vec)
{ ReadOrWrite_helper(is, vec); }
and also disappear the needs of explicating the V type.
Firstly, apologies, my explanation of my problem was bad and I'll do better in future.
Just in case anyone happens to read this and have a similar problem, I solved it by introducing two wrapper functions whose purpose is to explicitly state the template parameters:
template <class DataType>
void ParseData (std::ofstream & output_filestream, const DataType & data)
{
ReadOrWrite<std::ofstream, DataType> (output_filestream, data);
}
template <class DataType>
void ParseData (std::ifstream & input_filestream, DataType & data)
{
ReadOrWrite<std::ifstream, DataType> (input_filestream, data);
}
The important part is that this solution is scaleable: To handle each new data type I only need to write one ReadOrWrite function, with no unnecessary template parameters at function calls.
How the ParseData functions fit into the solution:
#include <iostream>
#include <fstream>
#include <vector>
// lots of useful typetraits:
#include <type_traits>
template <class S, class T = void>
struct is_vector : std::false_type {};
template <class S, class T>
struct is_vector <std::vector<S,T>> : std::true_type {};
template <typename Datatype>
inline constexpr bool is_vector_v = is_vector<Datatype>::value;
// Kinda similar format to my serialization library:
template <class Foo>
void Overload(const Foo & foo)
{
std::cout << "went to const" << std::endl;
}
template <class Foo>
void Overload(Foo & foo)
{
std::cout << "went to non-const" << std::endl;
}
// Special type trait specific to this library
// (within an anonymous namespace)
template <typename, typename Data>
struct vet_data_constness
: std::add_const<Data> {};
template <typename Data>
struct vet_data_constness <std::ifstream, Data>
: std::remove_const<Data> {};
template <typename StreamType, typename Data>
using vet_data_constness_t
= typename vet_data_constness<StreamType,Data>::type;
template <class StreamType, typename DataType>
std::enable_if_t<is_vector_v<DataType>>
ReadOrWrite (StreamType & filestream,
vet_data_constness_t<StreamType, DataType> & vector)
{
Overload(vector);
}
// These functions are simply for routing back to the ReadOrWrite
// funtions with explicit calls
template <class DataType>
void ParseData (std::ofstream & output_filestream, const DataType & data)
{
ReadOrWrite<std::ofstream, DataType> (output_filestream, data);
}
template <class DataType>
void ParseData (std::ifstream & input_filestream, DataType & data)
{
ReadOrWrite<std::ifstream, DataType> (input_filestream, data);
}
int main ()
{
std::ofstream output_filestream;
std::ifstream intput_filestream;
std::vector<int> vector;
ParseData(output_filestream, vector);
ParseData(intput_filestream, vector);
return 0;
}
Cant understand what is wrogn with code, second function definition or call of this function in main?
I think, but not sure, problem in call, cause without calling code compiles well. Compiler gcc
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
template<class T>
void show_element(T ob)
{
cout << ob << " ";
}
template<template<class> class S, class T>
void show_sequence(S<T> sequence)
{
for_each(sequence.begin(), sequence.end(), show_element<T>);
}
int main(int argc, char const *argv[])
{
std::vector<int> v(20, 0);
//here the problem
show_sequence<std::vector<int>, int>(v);
return 0;
}
std::vector isn't a template of one parameter, it takes an allocator type as well. You can use it as vector<T> simply because the second parameter has a default (std::allocator<T>).
As it's written, your template function cannot accept any standard container, since off the top of my head, none take just a single type parameter.
An approach that would work, and not require you to know how many template parameters a container requires, is to accept a container type (not template), and glean the value type from the container type.
template<class Seq>
void show_sequence(Seq const& sequence)
{
typedef typename Seq::value_type T;
for_each(sequence.begin(), sequence.end(), show_element<T>);
}
All standard containers have a value_type member, so this will work with any of them. Furthermore, it will work with any container that takes its cue from the standard library.
The problem is that std::vector is a template but std::vector<int> is a type.
When you are giving the second one to the function, you are giving one type and not a template.
So, you can rewrite your function as :
template<class S>
void show_sequence(S sequence)
Moreover, vector does not take only one template paramete but two (see StoryTeller answer)
It is similar to this question: https://stackoverflow.com/a/29493191/1889040
It is because vector is template of <type, allocator>
The code should be
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
template<class T>
void show_element(T ob)
{
cout << ob << " ";
}
template<template<class,class> class S, class T, class Allocator>
void show_sequence(S<T, Allocator> sequence)
{
for_each(sequence.begin(), sequence.end(), show_element<T>);
}
int main(int argc, char const *argv[])
{
std::vector<int> v(20, 0);
//here problem solved
show_sequence<vector, int, allocator<int> > (v);
show_sequence(v);
return 0;
}
I have a template where a function is overloaded so it can handle both an std::string parameter and the type of parameter that the template gets instantiated with. This works fine except when the template is being instantiated with std::string, since this results in two member functions with the same prototype. Thus, I have chosen to specialize that function for this particular case. However, it seems like the compiler (g++ 4.8.1 with flag -std=c++0x) never gets to the point where the specialization is actually overriding the primary template and it complains about the ambiguous overload the before it seems to realize that it should use the specialization. Is there a way to get around this?
#include <iostream>
template<class T>
struct A {
std::string foo(std::string s) { return "ptemplate: foo_string"; }
std::string foo(T e) { return "ptemplate: foo_T"; }
};
template<> //Error!
std::string A<std::string>::foo(std::string s) { return "stemplate: foo_string"; }
int main() {
A<int> a; //Ok!
std::cout << a.foo(10) << std::endl;
std::cout << a.foo("10") << std::endl;
//A<std::string> b; //Error!
//std::cout << a.foo("10") << std::endl;
return 0;
}
This results in compile errors, even if I don't instantiate at all with std::string (it seems that the compiler instantiates with std::string as soon as it sees the specialization and that it, before it actually processes the specialization, complains about the ambiguous overload which the specialization, in turn, will "disambiguate").
Compiler output:
p.cpp: In instantiation of 'struct A<std::basic_string<char> >':
p.cpp:10:27: required from here
p.cpp:6:14: error: 'std::string A<T>::foo(T) [with T = std::basic_string<char>; std::string = std::basic_string<char>]' cannot be overloaded
std::string foo(T e) { return "ptemplate: foo_T"; }
^
p.cpp:5:14: error: with 'std::string A<T>::foo(std::string) [with T = std::basic_string<char>; std::string = std::basic_string<char>]'
std::string foo(std::string s) { return "ptemplate: foo_string"; }
^
I would like it to just skip through the implementation of foo() in the primary template and use the specialization without considering the primary template foo(). Could it be done somehow, maybe with non-type template parameters, or do I have to make a fully specialized class template for std::string with all the code duplication it implies (I prefer not to use inheritance here)... Other suggestions?
When you specilize your member function you still get the double ambiguous declaration. Waht you need is to specialize the struct template:
template<>
struct A<std::string> {
std::string foo(std::string s) { return "ptemplate: foo_string"; }
};
If there are many members to the A struct maybe you can refactor:
template<typename T>
struct Afoo
{
std::string foo(T s) { ... }
std::string foo(std::string s) { ... }
};
template<>
struct Afoo<std::string>
{
std::string foo(std::string s) { ... }
};
template<typename T>
struct A : Afoo<T>
{
//a lot of code
};
I'm going to answer this myself since I've been diving deep into this subject today and I think these solutions are nice. All other posts up to this point have been contributive and have had attractive details with potential in other situations. However, I preferred to do it with these things in mind:
Avoid the use of more than one class template
Avoid too complicated specializations as far as possible
Avoid using inheritance and refactor into base and derived classes
Avoid the use of extra wrappers
Please feel free to comment before I accept it as my answer.
Another good and inspiring post on the subject focusing on the use of member function overloading rather than specializations can be found at explicit specialization of template class member function
Solution 1
template<class T>
struct A {
template<class V = T> std::string foo(T) { return "foo_T"; }
std::string foo(std::string) { return "foo_std::string"; }
std::string foo(const char *) { return "foo_const char *"; }
};
template<> template<>
std::string A<std::string>::foo(std::string s) { return foo(s); }
I think this is a dense and understandable solution allowing all class instantiations to use foo(std::string) and foo(const char *) (for passing a string as an rvalue). The use of a dummy template parameter effectively stops class instantiations with std::string from resulting in ambiguous overloads at the same time as the actual template argument hinders uncontrolled function instantiations with unpredictable function arguments. The only problem might come from a class instantiation with std::string that might use the template instead of the regular member function if explicitly called with foo<std::string>(std::string) in which way I would want the class to use the regular foo(std::string) instead of the function template for other instantiations. This is resolved by using a single template specialization.
Solution 2
template<class T>
struct A {
template<class V> std::string foo(V s) { return foo_private(s); }
private:
template<class V = T> std::string foo_private(T) { return "foo_T"; }
std::string foo_private(const char *) { return "foo_const char *"; }
std::string foo_private(std::string) { return "foo_std::string"; }
};
This version allows us to skip the specialization to the benefit of a second template in the class declaration.
Both versions used with:
int main() {
A<int> a;
std::cout << a.foo(10) << std::endl;
std::cout << a.foo("10") << std::endl;
A<std::string> b;
std::cout << b.foo<std::string>("10") << std::endl;
std::cout << b.foo("10") << std::endl;
return 0;
}
... outputted:
foo_T
foo_const char *
foo_const char *
foo_std::string
The error is saying that you ended up creating two method with the same signature.
That is because the struct has been templated with a std::string as parameter.
You should made the function as a templated function, using its own template parameters 'K' not related to the structure template parameter 'T'. Then you can achieve template specialization for the function only.
I admit that the solution I offer below, is a hacky solution indeed, but it does accomplish what you're trying to do and it's kinda funny. Please consider it thoroughly before you use this ;-)
I work around the issue by creating a new type, called FakeType, which can be constructed from your template-type T. The second overload of foo is now for FakeType<T> instead of T, so even when T == string there will be two different overloads:
template <typename T>
struct FakeType
{
T t;
FakeType(T const &t_): t(t_) {}
operator T() { return t; }
};
template <typename T>
struct A
{
string foo(string s) { return "ptemplate: foo_string"; }
string foo(FakeType<T> e) { return "ptemplate: foo_T"; }
};
For the case that T != string:
A<int>().foo("string"); // will call foo(string s)
A<int>().foo(1); // will call foo(FakeType<int> e)
In the latter case, the int will be promoted to a FakeType<int>, which can be used as a regular int through the conversion operator.
For the case that T == string:
A<string>().foo("string"); // will still call foo(string s)
Because the compiler will always prefer an overload for which no promotion is necessary.
PS. This approach assumes that foo is going to get its arguments either by value, or by const-reference. It will break as soon as you try to pass by reference (this can be fixed).