I've got a templated operator as class member:
struct A {
template <bool s=true> auto operator[](int ) {}
};
I specify the template parameter in the following (rather cumersome) way:
int main() {
A s;
s.template operator[]<false>(1);
}
This kind of destroys the 'beauty' of using an operator (aside from the fact that it is probably not a best practice to use templated operators; I use it in my code for having a conditionally const return type without re-implementing the logic and use the template only internally in the at implementation).
Is there a more condensed notation for specifying the template argument?
You can wrap the passed parameter in a template class which you can deduce, kind of like tag dispatching:
template<bool s>
struct A_index { // A shorter name based on your use case
int i;
};
struct A {
template<bool s> auto operator[](A_index<s> i_) {
int i = i_.i;
// Use `i`
}
auto operator[](int i) { (*this)[A_index<true>{ i }]; } // For your default = true
};
int main() {
A s;
s[A_index<false>{1}];
using t = A_index<true>;
s[t{0}];
}
Or you can have a helper template struct that has an A& reference where the struct has the template parameters:
struct A {
};
template<bool s = true>
struct A_index {
A& a;
auto operator[](int i) { }
};
int main() {
A s;
A_index<false> view{ s };
view[1];
}
Or you could just use non-operator member functions.
To implement a property system for polymorphic objects, I first declared the following structure:
enum class access_rights_t
{
NONE = 0,
READ = 1 << 0,
WRITE = 1 << 1,
READ_WRITE = READ | WRITE
};
struct property_format
{
type_index type;
string name;
access_rights_t access_rights;
};
So a property is defined with a type, a name and access rights (read-only, write-only or read-write). Then I started the property class as follows:
template<typename Base>
class property : property_format
{
public:
template<typename Derived, typename T>
using get_t = function<T(const Derived&)>;
template<typename Derived, typename T>
using set_t = function<void(Derived&, const T&)>;
private:
get_t<Base, any> get_f;
set_t<Base, any> set_f;
The property is associated to a base type, but may (and will) be filled with accessors associated to an instance of a derived type. The accessors will be encapsulated with functions accessing std::any objects on an instance of type Base. The get and set methods are declared as follows (type checking are not shown here to make the code minimal):
public:
template<typename T>
T get(const Base& b) const
{
return any_cast<T>(this->get_f(b));
}
template<typename T>
void set(Base& b, const T& value_)
{
this->set_f(b, any(value_));
}
Then the constructors (access rights are set to NONE to make the code minimal):
template<typename Derived, typename T>
property(
const string& name_,
get_t<Derived, T> get_,
set_t<Derived, T> set_ = nullptr
):
property_format{
typeid(T),
name_,
access_rights_t::NONE
},
get_f{caller<Derived, T>{get_}},
set_f{caller<Derived, T>{set_}}
{
}
template<typename Derived, typename T>
property(
const string& name_,
set_t<Derived, T> set_
):
property{
name_,
nullptr,
set_
}
{
}
The functions passed as arguments are encapsulated through the helper structure caller:
private:
template<typename Derived, typename T>
struct caller
{
get_t<Derived, T> get_f;
set_t<Derived, T> set_f;
caller(get_t<Derived, T> get_):
get_f{get_}
{
}
caller(set_t<Derived, T> set_):
set_f{set_}
{
}
any operator()(const Base& object_)
{
return any{
this->get_f(
static_cast<const Derived&>(object_)
)
};
}
void operator()(Base& object_, const any& value_)
{
this->set_f(
static_cast<Derived&>(object_),
any_cast<Value>(value_)
);
}
};
Now, considering these dummy classes.
struct foo
{
};
struct bar : foo
{
int i, j;
bar(int i_, int j_):
i{i_},
j{j_}
{
}
int get_i() const {return i;}
void set_i(const int& i_) { this->i = i_; }
};
I can write the following code:
int main()
{
// declare accessors through bar methods
property<foo>::get_t<bar, int> get_i = &bar::get_i;
property<foo>::set_t<bar, int> set_i = &bar::set_i;
// declare a read-write property
property<foo> p_i{"bar_i", get_i, set_i};
// declare a getter through a lambda
property<foo>::get_t<bar, int> get_j = [](const bar& b_){ return b_.j; };
// declare a read-only property
property<foo> p_j{"bar_j", get_j};
// dummy usage
bar b{42, 24};
foo& f = b;
cout << p_i.get<int>(f) << " " << p_j.get<int>(f) << endl;
p_i.set<int>(f, 43);
cout << p_i.get<int>(f) << endl;
}
My problem is that template type deduction doesn't allow me to declare a property directly passing the accessors as arguments, as in:
property<foo> p_i{"bar_i", &bar::get_i, &bar::set_i};
Which produces the following error:
prog.cc:62:5: note: template argument deduction/substitution failed:
prog.cc:149:50: note: mismatched types std::function<void(Type&, const Value&)> and int (bar::*)() const
property<foo> p_i{"bar_i", &bar::get_i, set_i};
Is there a way to address this problem while keeping the code "simple"?
A complete live example is available here.
std::function is a type erasure type. Type erasure types are not suitable for deduction.
template<typename Derived, typename T>
using get_t = function<T(const Derived&)>;
get_t is an alias to a type erasure type. Ditto.
Create traits classes:
template<class T>
struct gettor_traits : std::false_type {};
this will tell you if T is a valid gettor, and if so what its input and output types are. Similarly for settor_traits.
So
template<class T, class Derived>
struct gettor_traits< std::function<T(Derived const&)> >:
std::true_type
{
using return_type = T;
using argument_type = Derived;
};
template<class T, class Derived>
struct gettor_traits< T(Derived::*)() >:
std::true_type
{
using return_type = T;
using argument_type = Derived;
};
etc.
Now we got back to the property ctor:
template<class Gettor,
std::enable_if_t< gettor_traits<Gettor>{}, int> =0,
class T = typename gettor_traits<Gettor>::return_value,
class Derived = typename gettor_traits<Gettor>::argument_type
>
property(
const string& name_,
Gettor get_
):
property_format{
typeid(T),
name_,
access_rights_t::NONE
},
get_f{caller<Derived, T>{get_}},
nullptr
{
}
where we use SFINAE to ensure that our Gettor passes muster, and the traits class to extract the types we care about.
There is going to be lots of work here. But it is write-once work.
My preferred syntax in these cases would be:
std::cout << (f->*p_i)();
and
(f->*p_i)(7);
where the property acts like a member function pointer, or even
(f->*p_i) = 7;
std::cout << (f->*p_i);
where the property transparently acts like a member variable pointer.
In both cases, through overload of ->*, and in the second case via returning a pseudo-reference from ->*.
At the end of this answer is a slightly different approach. I will begin with the general problem though.
The problem is &bar::get_i is a function pointer to a member function while your alias is creating a function object which needs the class as additional template parameter.
Some examples:
Non member function:
#include <functional>
void a(int i) {};
void f(std::function<void(int)> func)
{
}
int main()
{
f(&a);
return 0;
}
This works fine. Now if I change a into a struct:
#include <functional>
struct A
{
void a(int i) {};
};
void f(std::function<void(int)> func)
{
}
int main()
{
f(std::function<void(int)>(&A::a));
return 0;
}
this gets the error:
error: no matching function for call to std::function<void(int)>::function(void (A::*)(int))'
because the std::function object also need the base class (as you do with your alias declaration)
You need a std::function<void(A,int)>
You cannot make your example much better though.
A way to make it a "bit" more easier than your example would maybe be this approach using CRTP.
#include <functional>
template <typename Class>
struct funcPtr
{
template <typename type>
using fun = std::function<void(Class,type)>;
};
struct A : public funcPtr<A>
{
void a(int i) {};
};
void f(A::fun<int> func)
{
};
int main()
{
f(A::fun<int>(&A::a));
return 0;
}
And each your "derived" classes derives from a funcPtr class which "auto generates" the specific alias declaration.
In this question I am led to a particular solution which involves partial specializations of templatized alias declarations. The generic case is described in this answer. Suppose I have a template class
template<typename T, ...>
class X {
// ....
};
Rather than leaving T free and specializing the other template parameters I am in a situation in which the other arguments depend on T, and on T alone. As a very concrete example (more manageable than the example in the other question) consider a template class
template<typename T, T absVal(T)>
class Number_impl {
private:
T _t;
public:
Number_impl(T t): _t(t) {}
T abs() const {return absVal(_t);}
};
Possible specializations are
Number_impl<int, std::abs>;
and
Number_impl<double, std::fabs>;
(I know there are overloaded abs versions, this is just for the sake of illustration. See my other example if you want).
Ideally I would like to define a template class Number depending on a single argument, the type, so that Number<int> is equal to
Number_impl<int, std::abs>;
and Number<double> is equal to
Number_impl<double, std::fabs>;
Something like the following (which doesn't work):
template<typename T>
using Number = Number_impl<T, nullptr>;
template<>
using Number<int> = Number_impl<int, std::abs>;
template<>
using Number<double> = Number_impl<double, std::fabs>;
Does anyone know if and how this can be made to work, or how the same can be achieved in a different way?
The normal way to do this kind of thing is the same way the standard library does it - with a traits class that you can specialise:
#include <iostream>
#include <cmath>
template<typename T> struct NumberTraits;
template<typename T, class Traits = NumberTraits<T>>
class Number {
private:
T _t;
public:
Number(T t): _t(t) {}
T abs() const {
return Traits::abs(_t);
}
};
template<> struct NumberTraits<int>
{
static int abs(int i) {
return std::abs(i);
}
};
template<> struct NumberTraits<double>
{
static double abs(double i) {
return std::fabs(i);
}
};
using namespace std;
auto main() -> int
{
Number<int> a(-6);
Number<double> b(-8.4);
cout << a.abs() << ", " << b.abs() << endl;
return 0;
}
expected output:
6, 8.4
You may add a layer:
template<typename T, T absVal(T)>
class Number_impl {
private:
T _t;
public:
Number_impl(T t): _t(t) {}
T abs() const {return absVal(_t);}
};
template<typename T> struct Number_helper;
template<> struct Number_helper<int> { using type = Number_impl<int, std::abs>; };
template<> struct Number_helper<double> { using type = Number_impl<double, std::fabs>; };
template<typename T>
using Number = typename Number_helper<T>::type;
Given the following declaration:
template<class T>
class A {
void run(T val) {
val.member ...
}
}
This code works fine if no pointers are used:
A<Type> a;
Type t;
a.run(t);
But using a pointer results in an error:
A<Type*> a;
Type* t = new Type();
a.run(t);
error: request for member ‘member’ which is of non-class type ‘T*’
Obviously in this case the member must be accessed via ->. What's the best way to handle this?
I found a solution on SO: Determine if Type is a pointer in a template function
template<typename T>
struct is_pointer { static const bool value = false; };
template<typename T>
struct is_pointer<T*> { static const bool value = true; };
...
if (is_pointer<T>::value) val->member
else val.member
But this is very verbose. Any better ideas?
You could use a simple pair of overloaded function templates:
template<typename T>
T& access(T& t) { return t; }
template<typename T>
T& access(T* t) { return *t; }
And then use them this way:
access(val).member = 42;
For instance:
template<typename T>
struct A
{
void do_it(T& val)
{
access(val).member = 42;
}
};
struct Type
{
int member = 0;
};
#include <iostream>
int main()
{
A<Type> a;
Type t;
a.do_it(t);
std::cout << t.member << std::endl;
A<Type*> a2;
Type* t2 = new Type(); // OK, I don't like this, but just to show
// it does what you want it to do...
a2.do_it(t2);
std::cout << t2->member;
delete t2; // ...but then, don't forget to clean up!
}
Here is a live example.
The best idea is probably to specialize your class for pointer types.
template<class T>
class A{ ...};
template<>
class A<T*> { //implement for pointers
};
If you feel that this is too verbose, you can use overload a get_ref function:
template<class T> T& get_ref(T & r) {return r;}
template<class T> T& get_ref(T* r) {return *r;}
template<class T>
class A {
void do(T val) {
get_ref(val).member ...
}
}
Consider the intention behind the following illegal C++11 code:
struct Base
{
template<typename U>
virtual U convert() = 0;
};
template<typename T>
struct Derived : Base
{
T t;
template<typename U>
virtual U convert() { return U(t); }
};
struct Any
{
Base* b;
template<typename U>
operator U() { return b->convert<U>(); }
};
int main()
{
Any a = ...;
string s = a; // s = a->b->t if T is convertible to string
// fails otherwise with compile error or runtime exception
// (either acceptable)
}
Is there a way to achieve the same or similiar effect with legal code?
(fyi the above way is illegal because templates may not be ‘virtual’)
Update:
struct Base
{
void* p;
type_info type;
};
template<typename T>
struct Derived : Base
{
Derived()
{
p = &t; // immovable
type = typeid(T);
}
T t;
};
struct Any
{
Base* b;
template<typename T = U, typename U>
operator U()
{
if (b->type != typeid(T))
throw exception();
T* t = (T*) b->p;
return U(*t);
}
};
Is this what you want?
struct Base
{
virtual void* convert(const std::type_info&) = 0;
};
template<typename T>
struct Derived : Base
{
virtual void* convert(const std::type_info& ti)
{ return typeid(T) == ti ? &t : nullptr; }
T t;
};
struct Any
{
Base* b;
template<typename U>
operator U()
{
if (auto p = b->convert(typeid(U)))
return *static_cast<U*>(p);
throw std::exception();
}
};
As the other answer says, it's hard to know exactly what you want as you've only shown invalid code, not explained what you're trying to achieve.
Edit oh I see now you want it to work for any convertible type, not just exact matches ... then no, you can't turn a type_info back into the type it represents, which would be needed for the derived type to test if the given type_info corresponded to a type that its stored type is convertible to. You need to know the correct type and specify it somehow, either explicitly or implicitly via deduction. If you then want to convert it to another type, you can do that separately:
Any a{ new Derived<int>() };
try {
char c = a; // throws
}
catch (...)
{
}
int i = a; // OK
char c = (int)a; // OK
Based on your update I think that this is what you are trying to do.
#include <typeinfo>
#include <exception>
#include <string>
template <typename T>
struct Any{
T* t;
Any():t(NULL){}
Any(const T& _t){
t=new T(_t);
}
template<typename U>
operator U(){
if(typeid(T)!=typeid(U) || t==NULL)
throw std::exception();
return *t;
}
};
int main (){
Any<std::string> a(std::string("Nothing"));
std::string b=a;
return 0;
};
If this doesn't help please explain in text not code what you are trying to achieve. It'll be useful to tell us also why you want to use those two extra classes Base and Derived.