I have created a type list. I then create a class using a template passing the type list. When I call the print function of the class with a some types not specified they are casted. How can I enforce the exact type at compile time? So if I use an unlisted type I get a compiler error.
Thanks.
template <class T, class U>
struct Typelist
{
typedef T Head;
typedef U Tail;
};
class NullType
{
};
typedef Typelist<int,Typelist<float,Typelist<char*,NullType> > > UsableTypes;
template<class T>
class MyClass
{
public:
void print(T::Head _Value) { std::cout << _Value; }
void print(T::Tail::Head _Value) { std::cout << _Value; }
void print(T::Tail::Tail::Head _Value) { std::cout << _Value; }
private:
};
MyClass<UsableTypes> testclass;
void TestMyClass()
{
int int_val = 100000;
float flt_val = 0.1f;
char* char_val = "Hi";
short short_val = 10;
std::string str_val = "Hello";
testclass.print( int_val ); // OK 8-)
std::cout << endl;
testclass.print( flt_val ); // OK 8-)
std::cout << endl;
testclass.print( char_val ); // OK 8-)
std::cout << endl;
testclass.print( short_val); // this compiles OK and works ??? 8-(
std::cout << endl;
testclass.print( str_val ); // compile error 8-)
std::cout << endl;
}
#Kerrek SB: Hi I thought it was going to help me with my next step, which was creating the print function depending on the t_list contents, Types and amounts of types. But I'm struggling to separate compile time processing and runtime processing. What I am trying to do is create a print function for each type in the list. So if the list has two types, two print functions will be created and if there are five types then five print functions will be created one for each type.
When I do this:
typedef Typelist<int,Typelist<float,Typelist<char*,NullType> > > UsableTypes;
MyClass<UsableTypes> newclass
Does this create three instance of MyClass one for each type in the list or does it create one instance and I have to create a print function for each type?
I feel I almost have all the blocks in my mind but just can’t fit them together. Any help you can offer would be gratefully received. Thanks.
Add a private function template
template<typename T> void print(T);
which doesn't need an implementation. This should catch all types for which no explicit print exists, and since it is private, it will give an error message.
You would have to make your print function into a template and then check whether the types match:
template <typename U>
void print(const U & u)
{
// use std::is_same<typename std::decay<T::Head>::type, typename std::decay<U>::type>::value
}
Here I'm stealing is_same and decay from <type_traits>, but if you don't have C++11, you can either take them from TR1 or from Boost, or just write them yourself, as they're very simple type modifier classes.
The conditional would best go into a static_assert, which is another C++11 feature, but there exist similar constructions for C++98/03 that produce a compile-time error under a certain condition.
You could take your arguments by non-const reference, forcing them to be the exact same type. However you can no longer use it with const variables or literals.
Related
I'm debugging an issue in a large C++ codebase where an attribute of a struct is occasionally being changed to a bad value. Unfortunately, the attribute is public and is accessed or changed in hundreds of places, so simply adding a breakpoint on a mutator is not possible. Also, I don't know the instance of the struct, so adding an address watchpoint wouldn't help.
Instrumenting the code would be a major job. However, a colleague helpfully suggested creating a proxy class which could wrap the existing type in the struct declaration. For example, instead of using MyType _type I would replace this with ChangeProxy<MyType> _type in the struct and the application should compile and work with the proxy taking the place of the direct type in the same manner as, for example, a smart pointer.
However, when I build an example, the implicit conversion operation in the template class doesn't appear to get invoked in type deduction. Here's the code:
#include <iostream>
class MyType {
long _n = 0;
public:
MyType() {}
MyType(const long n) : _n{n} {}
MyType& operator=(const long n) { _n = n; return *this; }
bool isZero() const { return _n != 0; }
};
template <class T>
class ChangeProxy {
public:
ChangeProxy() {}
ChangeProxy(const T& t) : _t{t} {}
ChangeProxy(const T&& t) : _t{std::move(t)} {}
ChangeProxy& operator=(const T& t) {onChange(t); _t = t; return *this;}
ChangeProxy& operator=(const T&& t) {onChange(t); _t = std::move(t); return *this;}
operator T() {return _t;}
private:
T _t;
void onChange(const T& newVal) { /* something here to notify me of changes */ };
};
struct MyStruct {
// MyType _type; // this works ...
ChangeProxy<MyType> _type; // .. but this doesn't
};
int main() {
MyStruct i;
std::cout << "i._type.isZero() : " << std::boolalpha << i._type.isZero() << std::endl;
i._type = 1;
std::cout << "i._type.isZero() : " << std::boolalpha << i._type.isZero() << std::endl;
return 0;
}
Unfortunately, when I build this I get the following errors:
proxy-variable~test.cpp:35:73: error: ‘class ChangeProxy<MyType>’ has no member named ‘isZero’
35 | std::cout << "i._type.isZero() : " << std::boolalpha << i._type.isZero() << std::endl;
| ^~~~~~
proxy-variable~test.cpp:37:73: error: ‘class ChangeProxy<MyType>’ has no member named ‘isZero’
37 | std::cout << "i._type.isZero() : " << std::boolalpha << i._type.isZero() << std::endl;
| ^~~~~~
So it seems that the compiler isn't deducing that it can cast a ChangeProxy<MyType> to a MyType. What have I done wrong here?
The context here doesn't let the compiler try out implicit conversions. Calling a member function on some object never does. You can force this by e.g.
std::cout << "i._type.isZero() : " << std::boolalpha <<
static_cast<MyType>(i._type).isZero() << '\n';
// ^^^^^^^^^^^^^^^^^^^ Here, enforce conversion
Another option would be:
MyStruct i;
const MyType& underlying = i._type; // Again, request conversion manually
std::cout << underlying.isZero() << '\n';
What you are doing is invoking a method on the class ChangeProxy<MyType> which indeed doesn't have any method isZero() defined on it, hence the compilation error. You could probably add something like
T const& operator()() const {return _t;}
And then call it using
i._type().isZero()
The reason that the wrapped i._type.isZero() can never work is that implicit conversions of the i._type object aren't considered for direct method calls, and you can't overload operator. like you can operator->.
It's nothing to do with type deduction, there's simply no mechanism in the language to do what you want.
Luckily, you're solving the wrong problem anyway.
... a colleague helpfully suggested creating a proxy class which could wrap the existing type in the struct declaration
Hmm, you didn't mention that here - or am I a colleague now?
an attribute of a struct is occasionally being changed to a bad value
Which attribute? Be specific!
In your code, you're treating the MyType instance as the problematic attribute. However, the only state in MyType is its long _n member.
Writing
class MyType {
ChangeProxy<long> _n = 0;
which is what I actually suggested when I referred to wrapping built-in types, avoids this problem entirely. You may of course need operator!= to make isZero work, but that's a normally overloadable operator.
Oddly the code in your question doesn't permit any mutation of _n anyway, so it's unclear how it can be getting a bad value. However, I assume this is just an artefact of a simplified example.
#include <iostream>
template<typename _OutType, typename _InType>
struct ConvertClass
{
_OutType operator()(_InType src)
{
return _OutType(src);
}
};
class OutClass
{
public:
OutClass(std::string str)
{
std::cout << "construct function works well!" << std::endl;
}
};
int main()
{
ConvertClass<OutClass, int>()(20); // this is wrong, because the OutClass only have one construct which takes the std::string type parameter.
// ConvertClass<OutClass, std::string>()(std::string("Hello!"));
/*
if (...) // So I wonder if there is any way that we can know whether the construct function is exists or not before we call the OutClass(int i) function
{
std::cout << "there is no such construct function of OutClass to take that parameter type" << std::endl;
return -1;
}
else
{
std::cout << "construct function works well!" << std::endl;
return 0;
}
*/
}
My Problem:
I know the main function is definitely wrong for the OutClass don't have the construct function OutClass(string str).
I wonder if there is a way only to change the Comment 1 section, the template class to make this file be compiled and linked successfully.
My English is not good, hoping you guys don't mind!
Thank you !
to my knowledge there is not runtime checking if given class is constructible using argument of given type
as said in my previous answer you can resort to Concepts and check the types at compiletime, but if clause does not work at compile time
To me it looks like the best solution would be indeed making a template class out of OutClass, then you have a single class with serves diverse purposes, dependent on you needs
one more edit to your code, I see that you pass the _OutType and _InType to your template.
In the setting where we have the following class template
template<class srcType>
class OutType:{
srcType src;
public:
OutType(srcType src) : src(src) {std::cout << "constructor works well!" << std::endl;}
}
then while invoking the class ConvertClass:
auto val = ConvertClass<OutClass<std::string>, std::string>()(std::string("Hello!"));
and also this will work:
auto val = ConvertClass<OutClass<int>, int>(20);
however, since operator() is not a static method you need first to construct object of class ConvertClass
In c++20 or even in c++17 you can in fact check if OutClass is constructible from int:
so your if clause should look like this
if(std::is_constructible<OutClass, int>::value) {
std::cout << "all is well" << std::endl;
}else{
std::cout << "you can't construct OutClass from int" << std::endl;
}
you can make the the following class template from the OutClass
template<class SrcType>
class OutClass {
SrcType src;
public:
OutClass(SrcType src) : src(src) {}
}
then in your code
return OutType<InType>(src);
if you need to check what the classes passed as template arguments actually can do (if they are arithmetic or additive or copy constructible e.g.) use Concepts from the C++20 standard
I'm learning some new concepts about c++ and I'm playing with them.
I wrote some piece of code that really confuses me in terms of how it works.
#include <iostream>
class aid {
public:
using aid_t = std::string;
void setaid(const std::string& s) {
aid_ = s;
}
const aid_t& getaid() const {
return aid_;
}
private:
aid_t aid_;
};
class c {
public:
using c_t = std::string;
void setc(const aid::aid_t& aid_val) {
if (aid_val.size() < 4)
c_ = "yeah";
else
c_ = aid_val + aid_val;
}
const c_t& getc() {
return c_;
}
private:
c_t c_;
};
template<typename ...Columns>
class table : public Columns... {
};
template <typename... Columns>
void f(table<Columns...>& t) {
t.setaid("second");
std::cout << t.getaid() << "\n";
}
void f2(table<aid>& t) {
t.setaid("third");
std::cout << t.getaid() << "\n";
}
int main() {
table<aid, c> tb;
tb.setaid("first");
std::cout << tb.getaid() << " " << "\n";
// f<c>(tb); // (1) doesnt compile, that seem obvious
f<aid>(tb); // (2) works?
f(tb); // (3) works too -- template parameter deduction
// f2(tb); // (4) doesnt work? worked with (2)...
}
The idea here is simple, I have some table with columns. And then I would like to create some functions that require only some set of columns and doesn't care if passed argument has some extra columns.
My confusion is mostly about points (2) and (4) in code... My intuition says it should be the same, why it isn't and (2) compiles and (4) doesn't? Is there any major topic I'm missing and should read up?
Is there a way to achieve this particular functionality?
In the second case, the compiler still deduces the rest of the template parameter pack, so that you get table<aid, c> & as the function parameter. This is different from (4) (table<aid> &).
[temp.arg.explicit]/9:
Template argument deduction can extend the sequence of template arguments corresponding to a template parameter pack, even when the sequence contains explicitly specified template arguments.
I want to call all types of functions from a single table.
(Consider returns types are all void)
To illustrate what I am talking about, here is some code that obviously does not work.
#include <iostream>
#include <map>
#include <functional>
void foo(int x){std::cout<<x;}
void bar(){std::cout<<"bar";}
std::map<std::string, std::function<void()>> map =
{
{"foo", foo},
{"bar", bar}
};
int main()
{
map["foo"](2);
map["bar"]();
}
I am not opposed to a C style solution.
You could declare your pointer an old style C function pointer to
a variadic function like:
foo(...);
bar(...);
std::map<void(*)(...)> map =
{
{"foo", foo},
{"bar", bar}
};
but then foo and bar have to follow the variadic calling convention with va_args, va_start
etc and you may only pull C PODs from the list. Don't know if its worth the hassle. The calling method still somehow has to know which number of args to pass.
Looks a bit as if you may rethink your design.
If for example this is supposed to be a command table for a kind of CLI it might be better to pass an std::vector<std::string> to each potential command and make it figure out if the vector has the correct size() for its purpose.
If you totally forsake the type system, you can use boost::any as long as you get all the types exactly right everywhere. Right now only works with explicitly making everything a std::function but I'm sure there's a workaround for that too (update added an overload for free functions):
class Functions
{
public:
template <typename... T>
void add_function(const std::string& name, void (*f)(T...))
{
fs[name] = std::function<void(T...)>{f};
}
template <typename... T>
void add_function(const std::string& name, std::function<void(T...)> f)
{
fs[name] = f;
}
template <typename... T>
void call(const std::string& name, T... args)
{
auto it = fs.find(name);
if (it != fs.end()) {
auto f = boost::any_cast<std::function<void(T...)>>(&it->second);
if (f) {
(*f)(args...);
}
else {
std::cout << "invalid args for " << name << std::endl;
}
}
else {
std::cout << "not found: " << name << std::endl;
}
}
private:
std::map<std::string, boost::any> fs;
};
void baz() {
std::cout << "baz" << std::endl;
}
int main() {
std::function<void()> foo = []{ std::cout << "foo" << std::endl; };
std::function<void(int)> bar = [](int i){ std::cout << "bar(" << i << ")" << std::endl;
};
Functions f;
f.add_function("foo", foo );
f.add_function("bar", bar);
f.add_function("baz", baz);
f.call("foo");
f.call("bar", 42);
f.call("baz");
}
Functional, yes. Good idea? Note also that f.call("bar", 42u) will fail because you have to get every type exactly right.
I changed a bit your approach, and be aware it's just an example, I'm pretty sure it won't compile like this, but it will give you an idea of what I had in mind.
You can register your functions in an additional struct, and then call the appropriate one, forwarding the parameters.
struct Funcs
{
std::function<void(int)> _f1;
std::function<void()> _f2;
template<typename args...>
void call(std::string&& f_name, args...)
{
if(f_name == "foo")
_f1(std::forward(args)...)
if(f_name == "bar")
_f2(std::forward(args)...)
}
}
int main()
{
Funcs f;
f.call("foo", 2);
}
If you really want to store any function, and can always figure out how to call it correctly, you can expand on Oncaphillis' approach and just go ahead and cast the function pointers:
void foo(int);
float bar(double, struct baz);
std::map<void(*)()> map = {
{"foo", (void(*)())foo},
{"bar", (void(*)())bar}
};
Then you can cast them back when you use them:
//code to make sure that map["foo"] is of type `void(*)(int)`
(*(void(*)(int))map["foo"])(42);
//code to make sure that map["bar"] is of type `float(*)(double, struct baz)`
float result = (*(float(*)(double, struct baz))map["foo"])(3.14159, (struct baz){ /*whatever*/});
As you see, it is no problem to call any type of function that way, without restricting to variadic ones. However, this approach is very error prone as you completely do away with the safety provided by the type system, and your casts must be 100% correct. Weird stuff may happen if you don't. That's the same problem as with using boost::any.
I want to put the result of this:
std::tr1::mem_fn(&ClassA::method);
Inside a variable, what is the type of this variable ?
That will look something like this:
MagicalType fun = std::tr1::mem_fn(&ClassA::method);
Also, what is the result type of std::tr1::bind ?
Thank you !
The return types of both std::tr1::mem_fn and std::tr1::bind are unspecified.
You can store the result of std::tr1::bind in a std::tr1::function:
struct ClassA {
void Func() { }
};
ClassA obj;
std::tr1::function<void()> bound_memfun(std::tr1::bind(&ClassA::Func, obj));
You can also store the result of std::tr1::mem_fn in a std::tr1::function:
std::tr1::function<void(ClassA&)> memfun_wrap(std::tr1::mem_fn(&ClassA::Func));
The return type of mem_fn and bind is unspecified. That means, depending on the arguments a different kind of object is returned, and the standard doesn't prescribe the details how this functionality must be implemented.
If you want to find out what the type is in a particular case with a particular library implementation (for theoretical interest, I hope), you can always cause an error, and get the type from the error message. E.g:
#include <functional>
struct X
{
double method(float);
};
int x = std::mem_fn(&X::method);
9 Untitled.cpp cannot convert 'std::_Mem_fn<double (X::*)(float)>' to 'int' in initialization
In this case, note that the type's name is reserved for internal use. In your code, you shouldn't use anything with a leading underscore (and a capital letter).
In C++0x, I suppose the return type would be auto :)
auto fun = std::mem_fn(&ClassA::method);
The function could be implemented in the following way (you thus also see the return type): You can try this piece of code here http://webcompiler.cloudapp.net/. Unfortunately, it makes use of variadic templates https://en.wikipedia.org/wiki/Variadic_template which are only part of the C++11 standard.
#include <iostream>
#include <string>
template <class R, class T, class... Args > class MemFunFunctor
{
private:
R (T::*mfp)(Args... ); //Pointer to a member function of T which returns something of type R and taking an arbitrary number of arguments of any type
public:
explicit MemFunFunctor(R (T::*fp)(Args... ) ):mfp(fp) {}
R operator()(T* t, Args... parameters)
{
(t->*mfp)(parameters... );
}
};
template <class R,class T, class... Args> MemFunFunctor<R,T,Args... > my_mem_fn( R (T::*fp)(Args... ) )
{
return MemFunFunctor<R,T,Args... >(fp);
}
class Foo //Test class
{
public:
void someFunction(int i, double d, const std::string& s )
{
std::cout << i << " " << d << " " << s << std::endl;
}
};
int main() //Testing the above code
{
Foo foo;
auto f = my_mem_fn(&Foo::someFunction);
f(&foo, 4, 6.7, "Hello World!" ); //same as foo.someFunction(4, 6.7, "Hello World!");
return 0;
}