I have the following scenario:
struct AP;
struct B
{
B() : m(2) {}
int m;
};
struct A : private B
{
A() : B(), n(1) {}
private:
int n;
friend AP;
};
struct AP
{
AP(A& a) : a_(a) {}
template<typename T>
struct A_B {
using type = typename std::enable_if< std::is_base_of< typename std::remove_reference<T>::type,
A >::value,
T >::type;
};
template<typename T>
operator typename A_B<T>::type()
{
return static_cast<T>(a_);
}
template<typename T>
typename A_B<T>::type get()
{
return static_cast<T>(a_);
}
int& n() { return a_.n; }
private:
A& a_;
};
int main()
{
A a;
AP ap(a);
ap.n() = 7;
const B& b = ap.get<const B&>();
//const B& b = ap; candidate template ignored: couldn't infer template argument 'T'
//auto b = static_cast<const B&>(ap); candidate template ignored: couldn't infer template argument 'T'
std::cout<<b.m;
}
The commented lines wouldn't compile. Clang++ notes that "candidate template ignored: couldn't infer template argument 'T'"
Why am I not able to get a reference to A's base with the cast operator?
I think the code would look much nicer that way.
The answer that you posted works, but is overkill unless you really want a static_assert message.
Classic templating works just fine in this instance because A is already convertible to B:
struct AP
{
AP(A& a) : a_(a) {}
template<typename T>
operator T()
{
return a_;
}
template<typename T>
T get()
{
return a_;
}
int& n() { return a_.n; }
private:
A& a_;
};
Demo
I found the answer here: http://www.mersenneforum.org/showthread.php?t=18076
This is the key: "when you want the compiler to deduce argument types, those types must not be dependent types"
With this it compiles:
template<typename T>
operator T()
{
static_assert(std::is_base_of< typename std::remove_reference<T>::type,A >::value,
"You may cast AP only to A's base classes.");
return static_cast<T>(a_);
}
Related
I have a template class that takes default member values.
template<class T = std::string>
struct A{
T val = {"val"};
};
However sometimes the default values do not make sense, for example:
A<int> a1; // cannot initialize int from "val"
Is there is good idiom to handle this issue?
I came up with this solution, which is quite verbose.
template<class T, class TT>
auto valid_or_default(TT&& other) ->
decltype(T{std::forward<TT>(other)}){return T{std::forward<TT>(other)};}
template<class T>
auto value_of_default(...){return T{};}
template<class T = std::string>
struct A{
T val = valid_or_default<T>("val");
};
(The other option is to set up a Boost.Fusion map to have a default value per type, but it is even more code and all the cases need to be handled.)
Update (thanks #Someprogrammerdude):
Another alternative for very specific cases (no valid based on syntax) can be done by specializing the constructor:
template<class T = std::string>
struct A{
T val;// = valid_or_default<T>("val");
A() : val{}{}
};
template<> A<std::string>::A() : val{"val"}{}
I still don't know what the original problem you try to solve is, or why you need to use a compile-time fixed-value for the initialization, but as it seems your structure is an aggregate you could simply use aggregate initialization:
template<typename T = std::string>
struct A
{
T val;
};
// ...
A a = { "val" };
A<int> b = { 1 };
Here is a C++17 solution:
template<class T, class TT>
auto valid_or_default(TT&& other)
{
if constexpr (std::is_constructible_v<T, TT>)
return T{std::forward<TT>(other)};
else
return T{};
}
Here's another option.
template <typename T>
T get_default_value()
{
return {};
}
template <>
std::string get_default_value<std::string>()
{
return "val";
}
template<class T = std::string>
struct A {
T val = get_default_value<T>();
};
I know one could check the existence of a particular method using expression SFINAE in C++11 as follows.
What I can't find though, is an example to do the same, checking method arguments as well. In particular I would like to match a method that takes a const parameter.
#include <iostream>
struct A
{
void method() const
{
return;
}
};
template <typename T, typename = std::string>
struct hasMethod
: std::false_type
{
};
template <typename T>
struct hasMethod<T, decltype(std::declval<T>().method())>
: std::true_type
{ };
int main() {
std::cout << hasMethod<A>::value << std::endl;
}
In reality I would like the hasMethod:: to match
void method(const Type& t) const
{
return;
}
What is the syntax to pass to decltype?
I have tried:
struct hasMethod<T, decltype(std::declval<T>().method(const int&))>
: std::true_type
but it obviously doesn't work.
I am trying to wrap my head around parameter packs and need a little help.
Looking at the contrived example below, Is there a way to compare Args to T and only allow bar() to compile if they match? For example if I create Task<void(int, char, float)> I want bar(float, char, float) not to compile but bar(int, char, float) to compile just fine. Is this even feasible?
template <typename... Types>
struct foo {};
template<typename T>
struct Task;
template<typename R, typename...Args>
struct Task<R(Args...)>
{
template<typename... T>
std::enable_if<is_same<T, Args>
void bar(T... args)
{
//do something here
}
};
int main()
{
Task<int(int)> task;
int a = 0;
float b = 1.0;
bool c = false;
//compiles
task.bar(a);
//none of these should compile
task.bar(b);
task.bar(c);
task.bar(a, b);
task.bar(a, b, c);
}
First, syntax should be:
template<typename R, typename...Args>
struct Task<R(Args...)>
{
template<typename... T>
std::enable_if<is_same<tuple<T...>, tuple<Args...> >::value > bar(T... args)
{
//do something here
}
};
Which compiles fine, because of SFINAE: while trying to instantiate bar(bool) for example, first instantiation fails with bool type, but an instantiation exists when performing conversion of parameter to int.
To get desired effect, you need the hard type check to happen after instantiating the template:
#include <type_traits>
#include <tuple>
template<typename T>
struct Task;
template<typename R, typename... Args>
struct Task<R(Args...)>
{
template<typename... OtherArgs>
void bar(OtherArgs... otherArgs)
{
static_assert(
std::is_same<std::tuple<Args...>, std::tuple<OtherArgs...> >::value,
"Use same args types !"
);
// Do something
}
};
int main()
{
Task<int(int)> task;
// Compiles fine
task.bar(1);
// Fails to compile
task.bar('u');
task.bar(0ul);
return 0;
}
Consider the following code:
#include <boost/iterator/iterator_facade.hpp>
#include <map>
// Class implements an stl compliant iterator to access the "sections" stored within a configuration.
template < typename _Iterator, typename _Reference >
class Section
: public boost::iterator_facade<
Section< _Iterator, _Reference >,
_Iterator,
boost::random_access_traversal_tag,
_Reference
>
{
private:
// Define the type of the base class:
typedef boost::iterator_facade<
Section< _Iterator, _Reference >,
_Iterator,
boost::random_access_traversal_tag,
_Reference
> base_type;
public:
// The following type definitions are common public typedefs:
typedef Section< _Iterator, _Reference > this_type;
typedef typename base_type::difference_type difference_type;
typedef typename base_type::reference reference;
typedef _Iterator iterator_type;
public:
explicit Section( const iterator_type it )
: m_it( it )
{ }
// Copy constructor required to construct a const_iterator from an iterator:
template < typename _U >
Section( const Section< _U, _Reference > it )
: m_it( it.m_it )
{ }
private:
// The following classes are friend of this class to ensure access onto the private member:
friend class boost::iterator_core_access;
template < typename _Iterator, typename _Reference > friend class Section;
void increment( ){ ++m_it; } // Advance by one position.
void decrement( ){ --m_it; } // Retreat by one position.
void advance( const difference_type& n ){ m_it += n }; // Advance by n positions.
bool equal( const this_type& rhs ) const{ return m_it == rhs.m_it; } // Compare for equality with rhs.
reference dereference( ) const { return m_it->second; } // Access the value referred to.
difference_type distance_to( const this_type& rhs ) const{ return rhs.m_it - m_it; } // Measure the distance to rhs.
private:
// Current "section" iterator:
iterator_type m_it;
};
struct Data
{
void f( ) const
{ }
};
typedef std::map< int, Data > map_type;
typedef Section< const map_type::const_iterator, const Data& > iterator_type;
map_type g_map;
iterator_type begin( )
{
return iterator_type( g_map.begin( ) );
}
void main( )
{
iterator_type i = begin( );
// i->f( ); // <--- error C2039: 'f' : is not a member of 'std::_Tree_const_iterator<_Mytree>'
( *i ).f( );
}
So the iterator facade shall return a reference to Data type. This works well when dereference operator is called but compile fails when operator->() is called. So I am a bit confused because operator->() tries to return a std::map::iterator. Any ideas ?
The iterator returns an iterator on dereference. To get the f part, you need to dereference twice.
It looks a lot like you misunderstood the meaning of the template arguments to iterator_facade. The second argument is not supposed to be any iterator type (this is what causes all your trouble). Instead you should use it to name your value_type.¹
From the way you specified the dereference operation (and Ref) and wanted to use it in main (i->f()) it looks like you just wanted to iterate the map's values. So, I'd rewrite the whole thing using more descriptive names as well, and here it is, working:
Live On Coliru
#include <boost/iterator/iterator_facade.hpp>
#include <map>
// Class implements an stl compliant iterator to access the "sections" stored within a configuration.
template <typename Map, typename Value = typename Map::mapped_type>
class MapValueIterator : public boost::iterator_facade<MapValueIterator<Map>, Value, boost::random_access_traversal_tag, Value const&> {
private:
// Define the type of the base class:
typedef Value const& Ref;
typedef boost::iterator_facade<MapValueIterator<Map>, Value, boost::random_access_traversal_tag, Ref> base_type;
public:
// The following type definitions are common public typedefs:
typedef MapValueIterator<Map> this_type;
typedef typename base_type::difference_type difference_type;
typedef typename base_type::reference reference;
typedef typename Map::const_iterator iterator_type;
public:
explicit MapValueIterator(const iterator_type it) : m_it(it) {}
// Copy constructor required to construct a const_iterator from an iterator:
template <typename U, typename V> MapValueIterator(const MapValueIterator<U,V> it) : m_it(it.m_it) {}
private:
// The following classes are friend of this class to ensure access onto the private member:
friend class boost::iterator_core_access;
template <typename U, typename V> friend class MapValueIterator;
void increment() { std::advance(m_it); } // Advance by one position.
void decrement() { std::advance(m_it, -1); } // Retreat by one position.
void advance(const difference_type &n) { std::advance(m_it, n); } // Advance by n positions.
bool equal(const this_type &rhs) const { return m_it == rhs.m_it; } // Compare for equality with rhs.
reference dereference() const { return m_it->second; } // Access the value referred to.
difference_type distance_to(const this_type &rhs) const { return rhs.m_it - m_it; } // Measure the distance to rhs.
private:
// Current iterator:
iterator_type m_it;
};
#include <iostream>
struct Data {
void f() const {
std::cout << __PRETTY_FUNCTION__ << "\n";
}
};
typedef std::map<int, Data> map_type;
template <typename Map>
MapValueIterator<Map> map_value_iterator(Map const& m) {
return MapValueIterator<Map>(m.begin());
}
int main() {
map_type g_map;
auto i = map_value_iterator(g_map);
i->f();
}
Which prints the output
void Data::f() const
as you'd expect.
Note that there are numerous places where I implemented the member functions using standard library facilities. Note as well, the iterator "mimics" random access, but it won't have the expected performance characteristics (increment is O(n)).
Final note: I'd recommend against having the implicit conversion constructor. I think you can do without it.
¹ The reference-type should typically be the same (but ref-qualified) except in rare cases where you actually "proxy" the values. This is an advanced topic and rarely should be used.
Using variadic template arguments together with a simple template argument I have experienced some strange behaviour of is_base_of when it was instantiated from a binded functor.
Here is the code:
template <class T, class Index>
class Base{};
template<typename T>
struct Checker {
typedef int result_type;
// Returns 1 if a given T type is descendant of Base<T,First>
template<typename First, typename ...Args>
result_type operator()(First&& first, Args&&... params)
{
return check(std::is_base_of<Base<T,First>, T>(),
std::forward<First>(first),
std::forward<Args>(params)...);
}
template<typename ...Args>
result_type check(const std::true_type&, Args&&... params)
{
return 1;
}
template<typename ...Args>
result_type check(const std::false_type&, Args&&... params)
{
return 0;
}
};
struct A {};
struct B : Base<B,int> {};
int main()
{
Checker<A> ch1;
std::cout<<ch1(3.14)<<std::endl;
Checker<B> ch2;
std::cout<<ch2(1 ,3.14)<<std::endl; // output is 1
std::cout<<std::bind(ch2, 1, 3.14)()<<std::endl; // output is 0 but it should be 1 !
return 0;
}
The program output is:
0
1
0
But I would expect:
0
1
1
Am I using the variadic templates in a wrong way? Is there any other (correct) way to get the first type of a variadic type list like Args? Why this is a problem only when it is used with the bind expression?
Note, if I am modifing the Base template to have only one template parameter, then the bind expression works:
template <class T>
class Base{};
template<typename T>
struct Checker {
typedef int result_type;
// Returns 1 if a given T type is descendant of Base<T>
template<typename ...Args>
result_type operator()(Args&&... params)
{
return check(std::is_base_of<Base<T>, T>(),
std::forward<Args>(params)...);
}
template<typename ...Args>
result_type check(const std::true_type&, Args&&... params)
{
return 1;
}
template<typename ...Args>
result_type check(const std::false_type&, Args&&... params)
{
return 0;
}
};
struct A {};
struct B : Base<B> {};
int main()
{
Checker<A> ch1;
std::cout<<ch1(3.14)<<std::endl;
Checker<B> ch2;
std::cout<<ch2(3.14)<<std::endl; // output is 1
std::cout<<std::bind(ch2, 3.14)()<<std::endl; // output is 1 this time!
return 0;
}
You're not getting the expected output because the data-type of First in your Checker function object when called after std::bind() is of type int&, not int.
Therefore std::is_base_of<Base<B,int&>, B> does not instantiate to a std::true_type for the call to Checker::check.
The problem is that std::bind is creating an object that internally stores the arguments for the function you are passing to it. Therefore there is a named l-value as a non-static data-member of the object returned by std::bind that is holding the value you passed as an argument to be bound to your function. When that non-static data-member is then passed to the r-value reference at the time you call the operator() of the functor, it's passed as an l-value reference, since it is no longer a temporary object. You would have a similar problem if you did something like:
int x = 1;
Checker<B> ch2;
std::cout<<ch2(x, 3.14)<<std::endl;
The named-value x is an l-value, and would be passed to the first argument in your operator() method as an l-value reference, not as temporary, since first is a r-value reference. Therefore your type would end up again as an int& and not an int, and you'd print a value of 0.
To fix this problem, you can do something like:
template<typename First, typename ...Args>
result_type operator()(First&& first, Args&&... params)
{
if (std::is_reference<First>::value)
{
return check(std::is_base_of<Base<T, typename std::remove_reference<First>::type>, T>(),
std::forward<First>(first),
std::forward<Args>(params)...);
}
else
{
return check(std::is_base_of<Base<T,First>, T>(),
std::forward<First>(first),
std::forward<Args>(params)...);
}
}
This will strip off the reference-type of the object and give you the results you want.
Unfortunately std::is_reference did not give me the expected result on a more complicated issue.
So finally I choosed providing the reference and const-reference overloads:
template<typename First, typename ...Args>
result_type operator()(First& first, Args&&... params)
{
return check(std::is_base_of<Base<T,First>, T>(),
first,
std::forward<Args>(params)...);
}
template<typename First, typename ...Args>
result_type operator()(const First& first, Args&&... params)
{
return check(std::is_base_of<Base<T,First>, T>(),
first,
std::forward<Args>(params)...);
}