I'm serializing template pack with fold expression using Boost.Serialization:
template <typename ... Args>
std::string toBytes(Args... args)
{
std::ostringstream buf;
boost::archive::binary_oarchive arch(buf);
(arch << ... << args);
return buf.str();
}
This works nice, but when I try to serialize a pointer to some basic type (say, char*), it chokes on it. I understand that Boost.Serialization doesn't serialize such types out of the box by intent. So, I want to provide a "default" way to serialize them.
To achieve that I want map each args element through some function f, so that f(char*) would return CharPtrWrapper and for other types that f should work as identity function.
My approach was:
template<typename T>
T f(T x) { return x; }
template<>
CharPtrWrapper f(char * x) { return CharPtrWrapper(x); }
but this code gives
error C2912: explicit specialization 'CharPtrWrapper f(char *)' is not a specialization of a function template
What's wrong with that and how do I solve this problem?
What's wrong with that and how do I solve this problem?
The problem is that your specialization isn't a specialization.
The generic f<>() is defined as:
template<typename T>
T f(T x) { return x; }
i.e., a template function that receives type T and returns the same type. So, a specialization of f<>() must return the same type that it receives.
However,
template<>
CharPtrWrapper f(char * x);
is not a valid specialization for f<>() because it receives char * and returns CharPtrWrapper.
A few valid specializations for f<>() are:
template <>
char const * f<char const *>(char const * x) { return x; }
// or
template <>
char const * f(char const * x) { return x; }
A solution, as suggested by n.m., would be to avoid specialization and use overloading instead. That means, from a practical point of view, to delete the "template<>" part and simply write:
CharPtrWrapper f(char * x) { return CharPtrWrapper(x); }
or better yet, receive a char const * instead of a char *.
So, I have a template class, which must call a callback function at some time. That callback function takes const T template as an argument.
I pass that function's pointer to a template class Boom<void*>. However, the const T argument of that callback is interpreted as just T.
But this is the case only with void*.
The code:
//main.cpp
void kolbek(const void* val)
{
if(val)
printf("Value is: %d\n", *((int*)val));
else
printf("Value ptr = NULL\n");
}
int main()
{
Boom<void*> bomba;
bomba.setCallback(kolbek); //error!
int* nuint = new int(5);
bomba.callCallback((void*)nuint);
delete nuint;
return 0;
}
//boom.h
template<typename T>
class Boom
{
private:
void (*someCallback)(const T) = nullptr;
public:
Boom(){ }
~Boom(){ }
void setCallback(void (*callbk)(const T));
void callCallback(const T val);
};
//boom.cpp
template<typename T>
void Boom<T>::setCallback(void (*callbk)(const T))
{
this->someCallback = callbk;
}
template<typename T>
void Boom<T>::callCallback(const T val)
{
if(someCallback)
(*someCallback)(val);
else
printf("Bad! Callback's NULL!\n");
}
template class Boom<int>;
template class Boom<void*>;
And when trying to compile this, an error is thrown:
error: invalid conversion from 'void (*)(const void*)' to 'void (*)(void*)' [-fpermissive]
error: initializing argument 1 of 'void Boom<T>::setCallback(void (*)(T)) [with T = void*]' [-fpermissive]
How to fix it? Seems like only void* pointers are wrongly interpreted.
Your problem comes from confusing two different consts. This is why it can be helpful to write T const instead of const T - it makes textual substitution not lie to you.
Boom's callback takes a T const which in your instatiation is void* const (not const void*!!): it's a const pointer to non-const void. kolbek's argument takes a void const* - a pointer to const void. Those aren't the same type. You can do a qualification conversion from the former to the latter, but not the other way around (you'd be casting away const!). This is your compiler error.
The simplest solution is not not have Boom add const. It's unnecessary. Use the T as provided and use Boom<const void*>.
In the case mentioned in comment you could create helper struct to make your template dereferenced parameter const:
template<class T>
struct ptr_constantizer {
using type = const T;
};
template<class T>
struct ptr_constantizer<T*> {
using type = const T*;
};
template<typename T>
class Boom
{
private:
void (*someCallback)(typename ptr_constantizer<T>::type) = nullptr;
public:
Boom(){ }
~Boom(){ }
void setCallback(void (*callbk)(typename ptr_constantizer<T>::type)) { }
void callCallback(const T val) { }
};
void foo(const void *ptr) {
}
void fooi(const int non_ptr) {
}
int main() {
Boom<void *> b;
Boom<int> bi;
b.setCallback(&foo);
bi.setCallback(&fooi);
}
The code assumes you are using c++11 as you used nullptr in your example...
Consider something like:
template <typename T>
void f(T& x)
{
....
}
Why does something like const int binds to f(T&)?
This seems to me kind of a violation of const-correctness. In fact, if f() takes a non-const T& reference, then it's very likely that f() will modify its argument (else, f() would have been defined as void f(const T&)).
In code like this:
template <typename T>
inline void f(T& x)
{
x = 0;
}
int main()
{
int n = 2;
f(n);
const int cn = 10;
f(cn);
}
the compiler tries to call f() with T = const int, then of course there is an error message because of the x = 0; assignment inside f()'s body.
This is the error message from GCC:
test.cpp: In instantiation of 'void f(T&) [with T = const int]':
test.cpp:13:9: required from here
test.cpp:4:7: error: assignment of read-only reference 'x'
x = 0;
^
But why does the compiler try to bind a const argument with a function template which takes a non-const parameter?
What's the rationale behind this C++ template rule?
T binds to const int.
To avoid that, you may use SFINAE:
template<typename T>
typename std::enable_if<!std::is_const<T>::value, void>::type
f(T& arg) {}
or deleted function:
template <typename T> void f(T& arg) {}
template <typename T> void f(const T&) = delete;
You can use std::enable_if plus e.g. std::is_const to avoid that T binds to a const type.
Re …
“What's the rationale behind this C++ template rule?”
it can possibly be found in Bjarne's design-and-evolution book, but about the most common rationale is that the rules have been chosen for simplicity and uniformity, and so it appears to be also here: treating some types in special ways would introduce needless complexity.
const int cn = 10;
That means 'cn' is const, you can't change it in anyway, anywhere and anytime.
More:
const int cia = 10;
int ia = 10;
The type of cia is different with ia. So T will be const int, not int.
typedef const int cint;
cint cia = 10;
int ia = 10;
T will be used as cint, not int.
I'm obviously misunderstanding something important about template specialization, because:
template<typename type> const type getInfo(int i) { return 0; }
template<> const char* getInfo<char*>(int i) { return nullptr; }
fails to compile with:
src/main.cpp:19:24: error: no function template matches function
template specialization 'getInfo'
while
template<typename type> type getInfo(int i) { return 0; }
template<> char* getInfo<char*>(int i) { return nullptr; }
works fine. How do I use const with template specializations? What is my rookie mistake?
I am using c++11 on clang++.
Note that, in the first example, the return type is const type, so the const applies to the whole type. If type is char* (as in your specialisation), then the return type is a char * const. This compiles just fine:
template<typename type> const type getInfo(int i) { return 0; }
template<> char* const getInfo<char*>(int i) { return nullptr; }
This makes sense - if specializing the type as a pointer. Why should the template have any say over what the pointer points to?
However, in this situation, I don't see much reason for having the return type be const.
If you need to be able to return string constant just use this:
template<typename type> type getInfo(int i) { return 0; }
template<> const char* getInfo<const char*>(int i) { return nullptr; }
What you tried to do is something like:
const int getInfo( int i ) { return 0; }
it does not make much sense.
How do I avoid implicit casting on non-constructing functions?
I have a function that takes an integer as a parameter,
but that function will also take characters, bools, and longs.
I believe it does this by implicitly casting them.
How can I avoid this so that the function only accepts parameters of a matching type, and will refuse to compile otherwise?
There is a keyword "explicit" but it does not work on non-constructing functions. :\
what do I do?
The following program compiles, although I'd like it not to:
#include <cstdlib>
//the function signature requires an int
void function(int i);
int main(){
int i{5};
function(i); //<- this is acceptable
char c{'a'};
function(c); //<- I would NOT like this to compile
return EXIT_SUCCESS;
}
void function(int i){return;}
*please be sure to point out any misuse of terminology and assumptions
Define function template which matches all other types:
void function(int); // this will be selected for int only
template <class T>
void function(T) = delete; // C++11
This is because non-template functions with direct matching are always considered first. Then the function template with direct match are considered - so never function<int> will be used. But for anything else, like char, function<char> will be used - and this gives your compilation errrors:
void function(int) {}
template <class T>
void function(T) = delete; // C++11
int main() {
function(1);
function(char(1)); // line 12
}
ERRORS:
prog.cpp: In function 'int main()':
prog.cpp:4:6: error: deleted function 'void function(T) [with T = char]'
prog.cpp:12:20: error: used here
This is C++03 way:
// because this ugly code will give you compilation error for all other types
class DeleteOverload
{
private:
DeleteOverload(void*);
};
template <class T>
void function(T a, DeleteOverload = 0);
void function(int a)
{}
You can't directly, because a char automatically gets promoted to int.
You can resort to a trick though: create a function that takes a char as parameter and don't implement it. It will compile, but you'll get a linker error:
void function(int i)
{
}
void function(char i);
//or, in C++11
void function(char i) = delete;
Calling the function with a char parameter will break the build.
See http://ideone.com/2SRdM
Terminology: non-construcing functions? Do you mean a function that is not a constructor?
8 years later (PRE-C++20, see edit):
The most modern solution, if you don't mind template functions -which you may mind-, is to use a templated function with std::enable_if and std::is_same.
Namely:
// Where we want to only take int
template <class T, std::enable_if_t<std::is_same_v<T,int>,bool> = false>
void func(T x) {
}
EDIT (c++20)
I've recently switched to c++20 and I believe that there is a better way. If your team or you don't use c++20, or are not familiar with the new concepts library, do not use this. This is much nicer and the intended method as outlines in the new c++20 standard, and by the writers of the new feature (read a papers written by Bjarne Stroustrup here.
template <class T>
requires std::same_as(T,int)
void func(T x) {
//...
}
Small Edit (different pattern for concepts)
The following is a much better way, because it explains your reason, to have an explicit int. If you are doing this frequently, and would like a good pattern, I would do the following:
template <class T>
concept explicit_int = std::same_as<T,int>;
template <explicit_int T>
void func(T x) {
}
Small edit 2 (the last I promise)
Also a way to accomplish this possibility:
template <class T>
concept explicit_int = std::same_as<T,int>;
void func(explicit_int auto x) {
}
Here's a general solution that causes an error at compile time if function is called with anything but an int
template <typename T>
struct is_int { static const bool value = false; };
template <>
struct is_int<int> { static const bool value = true; };
template <typename T>
void function(T i) {
static_assert(is_int<T>::value, "argument is not int");
return;
}
int main() {
int i = 5;
char c = 'a';
function(i);
//function(c);
return 0;
}
It works by allowing any type for the argument to function but using is_int as a type-level predicate. The generic implementation of is_int has a false value but the explicit specialization for the int type has value true so that the static assert guarantees that the argument has exactly type int otherwise there is a compile error.
Maybe you can use a struct to make the second function private:
#include <cstdlib>
struct NoCast {
static void function(int i);
private:
static void function(char c);
};
int main(){
int i(5);
NoCast::function(i); //<- this is acceptable
char c('a');
NoCast::function(c); //<- Error
return EXIT_SUCCESS;
}
void NoCast::function(int i){return;}
This won't compile:
prog.cpp: In function ‘int main()’:
prog.cpp:7: error: ‘static void NoCast::function(char)’ is private
prog.cpp:16: error: within this context
For C++14 (and I believe C++11), you can disable copy constructors by overloading rvalue-references as well:
Example:
Say you have a base Binding<C> class, where C is either the base Constraint class, or an inherited class. Say you are storing Binding<C> by value in a vector, and you pass a reference to the binding and you wish to ensure that you do not cause an implicit copy.
You may do so by deleting func(Binding<C>&& x) (per PiotrNycz's example) for rvalue-reference specific cases.
Snippet:
template<typename T>
void overload_info(const T& x) {
cout << "overload: " << "const " << name_trait<T>::name() << "&" << endl;
}
template<typename T>
void overload_info(T&& x) {
cout << "overload: " << name_trait<T>::name() << "&&" << endl;
}
template<typename T>
void disable_implicit_copy(T&& x) = delete;
template<typename T>
void disable_implicit_copy(const T& x) {
cout << "[valid] ";
overload_info<T>(x);
}
...
int main() {
Constraint c;
LinearConstraint lc(1);
Binding<Constraint> bc(&c, {});
Binding<LinearConstraint> blc(&lc, {});
CALL(overload_info<Binding<Constraint>>(bc));
CALL(overload_info<Binding<LinearConstraint>>(blc));
CALL(overload_info<Binding<Constraint>>(blc));
CALL(disable_implicit_copy<Binding<Constraint>>(bc));
// // Causes desired error
// CALL(disable_implicit_copy<Binding<Constraint>>(blc));
}
Output:
>>> overload_info(bc)
overload: T&&
>>> overload_info<Binding<Constraint>>(bc)
overload: const Binding<Constraint>&
>>> overload_info<Binding<LinearConstraint>>(blc)
overload: const Binding<LinearConstraint>&
>>> overload_info<Binding<Constraint>>(blc)
implicit copy: Binding<LinearConstraint> -> Binding<Constraint>
overload: Binding<Constraint>&&
>>> disable_implicit_copy<Binding<Constraint>>(bc)
[valid] overload: const Binding<Constraint>&
Error (with clang-3.9 in bazel, when offending line is uncommented):
cpp_quick/prevent_implicit_conversion.cc:116:8: error: call to deleted function 'disable_implicit_copy'
CALL(disable_implicit_copy<Binding<Constraint>>(blc));
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Full Source Code: prevent_implicit_conversion.cc
Well, I was going to answer this with the code below, but even though it works with Visual C++, in the sense of producing the desired compilation error, MinGW g++ 4.7.1 accepts it, and invokes the rvalue reference constructor!
I think it must be a compiler bug, but I could be wrong, so – anyone?
Anyway, here's the code, which may turn out to be a standard-compliant solution (or, it may turn out that that's a thinko on my part!):
#include <iostream>
#include <utility> // std::is_same, std::enable_if
using namespace std;
template< class Type >
struct Boxed
{
Type value;
template< class Arg >
Boxed(
Arg const& v,
typename enable_if< is_same< Type, Arg >::value, Arg >::type* = 0
)
: value( v )
{
wcout << "Generic!" << endl;
}
Boxed( Type&& v ): value( move( v ) )
{
wcout << "Rvalue!" << endl;
}
};
void function( Boxed< int > v ) {}
int main()
{
int i = 5;
function( i ); //<- this is acceptable
char c = 'a';
function( c ); //<- I would NOT like this to compile
}
I first tried PiotrNycz's approach (for C++03, which I'm forced to use for a project), then I tried to find a more general approach and came up with this ForcedType<T> template class.
template <typename T>
struct ForcedType {
ForcedType(T v): m_v(v) {}
operator T&() { return m_v; }
operator const T&() const { return m_v; }
private:
template <typename T2>
ForcedType(T2);
T m_v;
};
template <typename T>
struct ForcedType<const T&> {
ForcedType(const T& v): m_v(v) {}
operator const T&() const { return m_v; }
private:
template <typename T2>
ForcedType(const T2&);
const T& m_v;
};
template <typename T>
struct ForcedType<T&> {
ForcedType(T& v): m_v(v) {}
operator T&() { return m_v; }
operator const T&() const { return m_v; }
private:
template <typename T2>
ForcedType(T2&);
T& m_v;
};
If I'm not mistaken, those three specializations should cover all common use cases. I'm not sure if a specialization for rvalue-reference (on C++11 onwards) is actually needed or the by-value one suffices.
One would use it like this, in case of a function with 3 parameters whose 3rd parameter doesn't allow implicit conversions:
function(ParamType1 param1, ParamType2 param2, ForcedType<ParamType3> param3);