I've seen lots of SO questions about specialization in the context of methods, but not functions belonging to classes. I'm having a hard time translating the knowledge passed on from those questions to my problem here.
I'm mucking around with a class I created in the past to learn and I would like to have a specialization for arithmetic types.
template <typename T>
class Vector3
{
public:
T x;
T y;
T z;
public:
operator std::string() const;
}
This is the specialization I am trying to do:
template<typename T = std::enable_if<std::is_arithmetic<T>::value, T>::type>
inline Vector3<T>::operator std::string() const {
std::stringstream ss;
ss << "NOT NUMBER {" << x << ", " << y << ", " << z << "}";
return ss.str();
}
template<typename T = std::enable_if<!std::is_arithmetic<T>::value, T>::type>
inline Vector3<T>::operator std::string() const {
std::stringstream ss;
ss << "NUMBER {" << x << ", " << y << ", " << z << "}";
return ss.str();
}
However when I try to compile, I get
error C2995: 'Vector3::operator std::string(void) const': function
template has already been defined
When I google this, it is usually cases where people have defined their class/method in the CPP file as well as the header file. As I only do this in the header file, I can only assume the enable_if is not correct. When I look at other examples, they just do specialization on , , but I'd like to use the is_arithmitic way.
What am I doing wrong? Thanks in advance
The default here:
template<typename T = XXX>
inline Vector3<T>::operator std::string() const { ... }
doesn't matter at all, there's no deduction going on at this point, and T is already defined. It's legal, but it's just noise.
Now, you can't partially specialize a member function in a class template either, but we can dispatch on traits:
template <class T>
class Vector3 {
public:
// ...
operator std::string() const {
return as_string(std::is_arithmetic<T>{});
}
private:
std::string as_string(std::true_type ) {
// implementation for arithmetic types
}
std::string as_string(std::false_type ) {
// implementation for non-arithmetic types
}
};
Barry's answer is perfect.
Here is some explanation and suggestions:
http://en.cppreference.com/w/cpp/types/enable_if
"A common mistake is to declare two function templates that differ only in their default template arguments. This is illegal because default template arguments are not part of function template's signature, and declaring two different function templates with the same signature is illegal."
Related
I have a class that wraps a std::map, I have simplified it below. I wanted to implement a to_string() function which streams the first and second map entries into a stringstream with operator << - then returns the string result.
This works ok for int, float, string etc... anything that can be streamed basically.
But enum class xzy : int {...}; can't be stream -or it must be static_cast first. But in my template if I put static_cast around x.second then it will break other template types.
I want to know how I can deal with this. My first idea is to try to use type traits to detect if the type is integral (and then static cast it) otherwise just rely on the normal operator << function.
here is the class:
template<typename T1, typename T2>
class map_wrapper
{
public:
std::map<T1, T2> m_map;
std::map<T1, T2> &map() {return m_map;}
std::string to_string()
{
std::stringstream ss;
for (const auto &item : m_map)
{
// <----------------------- ISSUE HERE
// So I want this to handle as many types as possible
// Maybe I can do some sort of if type traits == integral then static cast?
ss << item.first << ", " << static_cast<int>(item.second) << "\n";
//ss << item.first << ", " << item.second << "\n";
}
return ss.str();
}
};
here is my test code:
enum class types : int
{
type1,
type2,
type3
};
int main()
{
// This is all ok
map_wrapper<int, int> int_map;
int_map.map() = {{1, 2}, {3, 4}};
std::cout << int_map.to_string() << std::endl;
// This only works if I static_cast the enum types to an int within to_string()
map_wrapper<int, types> type_map;
type_map.map() = {{1, types::type1}, {2, types::type2}};
std::cout << type_map.to_string() << std::endl;
return 0;
}
I have annotated the parts that don't work as I want them to.
Live editable example: https://godbolt.org/z/rh8Y5v
update
Note the types enum is just an example - I would like it to work with any enum class ideally
You cannot specialize a single member function, you would need to specialize the whole class. If you only need it for this function, I suggest providing a template operator overload:
template<typename Enum,
typename = std::enable_if_t<std::is_enum_v<Enum>>>
std::ostream& operator<< (std::ostream& out, Enum e)
{
return out << static_cast<int>(e);
}
See it online
This operator will accept any enum or enum class. If you want to only accept enum class, you can use std::is_scoped_enum from C++23 or roll out your own one (there's a possible implementation in cppreference to help).
Note that you can still provide overloads if you want to pretty print a particular enum (which would require another full class specialization if we went with that).
Short question;
I don't get why this syntax exists:
template <int in>
void test(){
std::cout << in << std::endl;
}
int main(){
test<5>();
return 0;
}
When you can do the same without templates:
void test(test in){
std::cout << in << std::endl;
}
int main(){
test(5);
return 0;
}
How would you do this without templates?
template<std::size_t n> void f() {
char buf[n];
}
Besides, passing values as arguments requires extra arguments, extra run-time overhead, not necessarily needed when you know a value is actually a compile-time constant. With classes, it would require an extra member, and an extra construction argument for a class which might otherwise be empty and trivial.
What you have shown is not partial specialization.
Here an example of specialization (in this case full specialization):
#include <iostream>
template <int in, int in2>
void test_template(){
std::cout << in << std::endl;
}
template <>
void test_template<1>(){
std::cout << "one" << std::endl;
}
template <>
void test_template<2>(){
std::cout << "two" << std::endl;
}
int main()
{
test_template<1>();
test_template<2>();
test_template<3>();
test_template<4>();
}
And it is useful to handle certain template parameters in a special way. (Partial specialization, is if you have multiple template arguments and specialize all except one of them)
Regarding your example, the use-case you have shown does not illustrate where it can be useful, as it indeed does not make much a difference to use a regular function there.
But if you look at functions like std::make_shared or std::make_pair there is no way how you could solve that without using templates:
template< class T1, class T2 >
std::pair<T1,T2> make_pair(T1 t, T2 u) {
return std::pair<T1,T2>(t,u);
}
They are not "the same".
The two versions of test are very different. I rename them to avoid confusion and merely list some differences:
template <int in>
void test_template(){
std::cout << in << std::endl;
}
void test_fun(test in){
std::cout << in << std::endl;
}
test_template is a template. It is not a function. For example it is not possible to get a pointer to test_template:
auto f_ptr1 = &test_template; // doesn't make sense
auto f_ptr2 = &test_fun; // OK
The template parameter has to be known at compile time:
int x;
std::cin >> x;
test_template<x>(); // error: x must be known at compile time
test_fun(x); // OK
On the other hand, once you did instantiate the template you get a function with no parameters:
auto f = &test_template<5>;
f();
auto g = &test_template<6>;
g();
Similar you can only do with test_fun when you wrap it into another function (ie overhead).
... and more.
PS: There is no partial specialization in your code.
In my code, I use variadic template functions for the logging purpose. But when I use std::endl as parameter, I get the following compiler error:
Error: no matching function for call to 'LOG_ERROR(const char [14],
int&, )' LOG_ERROR("Sum of x+y
= ", z, std::endl);
note: candidate: 'void LOG_ERROR()' inline void LOG_ERROR() {
note: candidate expects 0 arguments, 3 provided
My Code:
#include <iostream>
inline void LOG_ERROR() {
std::cout << std::endl;
}
template<typename First, typename ...Rest>
void LOG_ERROR(First && first, Rest && ...rest){
std::cout << std::forward<First>(first);
LOG_ERROR(std::forward<Rest>(rest)...);
}
int main() {
int foo=40;
LOG_ERROR("My foo = ", foo, std::endl);
}
The code works fine with "\n" but I would love to learn why it fails with std::endl and how I can fix it
Long story short - std::endl is function template which template arguments can't be deduced while passing. You can help Your compiler this way:
LOG_ERROR("My foo = ", foo, std::endl<char, std::char_traits<char>>);
As much as I feel this is ugly piece of code it works perfectly.
Until someone comes with a better solution, you can use a trivial wrapper with an appropriate operator overload:
struct EndlWrap {};
std::ostream& operator << (std::ostream& os, EndlWrap) {
return os << std::endl;
}
which should be usable like this:
LOG_ERROR("My foo = ", foo, EndlWrap{});
This has an advantage when your logging destination might be a non-standard stream, i.e., the template arguments of std::endl can still be deduced when it's <<'d into the stream.
std::endl is not a character type or any other type. It is output stream manipulator. Its return type is output stream.
So, you can not pass it without typecasting. Please look here
You can use defaulted template parameters and defaulted function arguments instead of a variadic template.
The code is less clean and you will have to choose a limitation on the number of parameters, but it will do the job:
template<class...>
inline void LOG_ERROR_();
template<>
inline void LOG_ERROR_<>() {
std::cout << std::endl;
}
template<typename First, typename ... Rest>
void LOG_ERROR_(First && first, Rest && ...rest){
std::cout << std::forward<First>(first);
LOG_ERROR_<Rest...>(std::forward<Rest>(rest)...);
//could be cleaner with if constexpr
}
using manip_t = std::basic_ostream<char>&(*)(std::basic_ostream<char>&);
std::basic_ostream<char>& no_manip(std::basic_ostream<char>& o){
return o;
}
template<typename A=manip_t
,typename B=manip_t, typename C= manip_t
,typename D=manip_t // to be continued
>
inline void LOG_ERROR(A&& a=no_manip, B&& b=no_manip,C&& c=no_manip
,D&& d=no_manip /*to be continued*/){
LOG_ERROR_<A,B,C,D/*to be continued*/>(
std::forward<A>(a),std::forward<B>(b),std::forward<C>(c),
std::forward<D>(d)/*to be continued*/);
}
Depending on the compiler this code could produce ugly assembly. One solution is to write an overload for each possible number of argument, or have a good knowldge of compiler specific function attributes (always_inline,etc...)
I am constructing a library that makes use of expression templates, where I make heavily use of templated functions in classes. All my code is running and recently I decided to make the main class templated to allow for using it on data of different kinds. However, I can no longer specialize my functions. How do I solve this? I have attached a small test program that shows the problem.
My previous Animal class was not templated and then this code works fine.
#include<iostream>
#include<vector>
// Example templated class with templated function
template<class T>
class Animals
{
public:
template<class X>
void printFood(const X& x) const { std::cout << "We eat " << x << "!" << std::endl; }
private:
std::vector<T> animals;
};
// How do I specialize?
template<class T> template<>
void Animals<T>::printFood(const unsigned int& x) const { std::cout << "We don't want to eat " << x << "!" << std::endl; }
// Main loop;
int main()
{
Animals<double> doubleAnimals;
const int banana = 42;
doubleAnimals.printFood(banana);
const unsigned int apple = 666;
doubleAnimals.printFood(apple);
return 0;
}
This simply isn't possible
[temp.expl.spec]
16 In an explicit specialization declaration for a member of a class template or a member template that appears in namespace scope, the member template and some of its enclosing class templates may remain unspecialized, except that the declaration shall not explicitly specialize a class member template if its enclosing class templates are not explicitly specialized as well.
You should specialize your class first. Then specialize function:
template<> template<>
void Animals<double>::printFood(const unsigned int& x) const { std::cout << "We don't want to eat " << x << "!" << std::endl; }
You can't partially specialize template members of non-specialized template class. This is consistent with prohibiting partial specialization of template functions (think of template class as the member function's first parameter). Use overloading instead:
template<class T>
class Animals
{
public:
template<class X>
void printFood(const X& x) const { std::cout << "We eat " << x << "!" << std::endl; }
void printFood(const unsigned int& x) const { std::cout << "We don't want to eat " << x << "!" << std::endl; }
private:
std::vector<T> animals;
};
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).