boost::enable_if_c does not seem to work [duplicate] - c++

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
How to use enable_if to enable member functions based on template parameter of class
I have a class template:
template<typename T, size_t N> class Vector
I want to enable constructors for specific N, so I do:
Vector(typename boost::enable_if_c<N==2, T>::type const &e0, T const &e1) {
data[0] = e0;
data[1] = e1;
}
But compiler (MSVC 2010 SP1) gives me an error instead of applying SFINAE. The error is:
error C2039: 'type' : is not a member of 'boost::enable_if_c<B,T>'
with
[
B=false,
T=float
]
What is the problem? Is it a known problem? How can I fix it? Is it the only solution to use static_assert?
Edit: GCC does not succeed either: http://ideone.com/7Ejo8

You can't use enable_if to allow/disallow member functions based on template parameters of the class: enable_if can only be applied on function or class templates.
In your case, the only solution I can think of is specializing the entire class, either using enable_if or more simply with partial specialization. You can put the common members in a common base class, to avoid repeating them:
#include <cstdio>
template<typename T, std::size_t N>
struct VectorCommon
{
std::size_t size() { return N; }
void add(T const & element) { }
};
template <typename T, std::size_t N>
struct Vector : VectorCommon<T, N>
{
};
template <typename T>
struct Vector<T, 2> : VectorCommon<T, 2>
{
Vector(T const & e0, T const & e1) {}
};
int main()
{
//Vector<int, 100> v100(12, 42); // compile error
Vector<char, 2> v2('a', 'b'); // ok
}

Related

How to specialize a template-class with doubles?

I write a template class dependent on a given type and variadic types, like so:
template<typename ConstType,typename...Inputs>
class ConstantTensor;
Then I write another class, which is generally defined in this way (assume wrong_type whatever type you want, but which is different from the following specialization ):
template<typename T>
class X{
public:
using type=wrong_type;
}
And I also have a specialization of this kind:
template<typename ConstType,typename...Inputs>
class X< ConstantTensor< ConstType ,Inputs...>>
{
public:
using type=right_type;
}
My problem is that, if I define the type ConstantTensor<ConstType,double> and then I want to use X<ConstantTensor<ConstType,double>>::type, the general case is called and not the specialization. So I obtain wrong_type instead of right_type. I guess it has to deal with the double type...Could you explain me why and how can I solve this issue? Thank you in advance.
EDIT:
Here a snippet of code, I hope it works:
class Scalar
{};
template<typename ConstType,typename...Inputs>
class ConstantTensor
{
public:
constexpr ConstantTensor(const Inputs&...inputs)
{}
};
template<typename ConstType,typename...Inputs>
constexpr auto Constant(const Inputs&...inputs)
{return ConstantTensor<ConstType,Inputs...>(inputs...);}
template<typename T>
class X{
public:
using type=int;
};
template<typename ConstType,typename...Inputs>
class X<ConstantTensor<ConstType,Inputs...>>{
public:
using type=char;
};
int main()
{
constexpr auto delta=Constant<Scalar>(2.0);
using type= X<decltype(delta)>::type; // this is int not char
}
The problem is that
constexpr auto delta=Constant<Scalar>(2.0);
is a constexpr variable; so it's also const.
So decltype(delta) isn't ConstantTensor<Scalar> but is a ConstantTensor<Scalar> const.
You can verify adding const in partial specialization declaration
template<typename ConstType,typename...Inputs>
class X<ConstantTensor<ConstType,Inputs...> const>{ // <-- added const
public:
using type=char;
};
Now you get that type is char.
-- EDIT --
The OP asks
Is there a short/elegant way to deal with both cases, const and non const, without duplicating the code?
I don't know if it's elegant, but it seems to me short enough: you can use a sort of self-inheritance adding the following partial specialization.
template <typename T>
class X<T const> : public X<T>
{ };
So X<ConstantTensor<Scalar> const> inherit from X<ConstantTensor<Scalar>>.

Hash an object using its base class' partial template specialization for std::hash

I have a wrapper class for std::string that serves as base class for several others. Instances of the subclasses will be used as keys in std::unordered_set so I need to provide a hash function for them. Since the hash is only dependent on the std::string stored in the base class, I do not want to write a hash function for every subclass but rather use the one from the wrapper class.
This is how I would like to solve the problem:
#include <string>
#include <unordered_set>
class Wrapper {
public:
std::string name;
size_t _hash;
explicit Wrapper(std::string str) : name(str), _hash(std::hash<std::string>()(name)) {}
size_t hash() const { return _hash; }
};
class Derived : public Wrapper {};
namespace std {
template <> struct hash<Wrapper> {
std::size_t operator()(const Wrapper &k) const { return k.hash(); }
};
template <typename T> struct hash<std::enable_if_t<std::is_base_of_v<Wrapper, T>>> {
std::size_t operator()(const T &k) const { return k.hash(); }
};
} // namespace std
int main(void) {
std::unordered_set<Wrapper> m1;
std::unordered_set<Derived> m2;
}
This does not compile of course, since T cannot be deduced. Clang says:
20:30: error: class template partial specialization contains a template parameter that cannot be deduced; this partial specialization will never be used
20:20: note: non-deducible template parameter 'T'
And g++ says:
hash_subclass.cpp:21:30: error: template parameters not deducible in partial specialization:
template <typename T> struct hash<std::enable_if_t<std::is_base_of_v<Wrapper, T>>> {
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
hash_subclass.cpp:21:30: note: 'T'
I have found this solution, but I would like to avoid using a macro. Also, this goes against what I expect from inheritance.
Is there a solution for this? Can a subclass inherit its base class' specialization of std::hash?
Also, I'm not 100% sure about my use of std::enable_if and std::is_base_of. Could you tell me whether this would work assuming T could be deduced?
IRC, the problem with std::enable_if is that it does not work for classes with a single template parameter. Consequently, you cannot specialize std::hash by using std::enable_if.
However, you can make your own hasher as follows:
template <typename T, typename Enable = std::enable_if_t<std::is_base_of_v<Wrapper, T>>>
struct WrapperHasher {
std::size_t operator()(const T& k) const { return k.hash(); }
};
And then use it as a second template argument of std::unordered_set:
std::unordered_set<Wrapper, WrapperHasher<Wrapper>> m1;
std::unordered_set<Derived, WrapperHasher<Derived>> m2;
But in your case, you can define a wrapper much more simply as:
struct WrapperHasher {
std::size_t operator()(const Wrapper& k) const { return k.hash(); }
};
And then write:
std::unordered_set<Wrapper, WrapperHasher> m1;
std::unordered_set<Derived, WrapperHasher> m2;

Full class template specialization with forward declarations

It appears a forward declaration is causing an issue when specializing some template functions within a template class. I am specializing the class also as it's necessary in order to specialize the function, and this seems to be causing the issue.
Edit: Second question about pre-creating functions for process function:
processor.H
namespace OM{
template<typename MatchT> //fwd decl. ERROR 2. see below.
class Manager;
template<typename MatchT>
class Processor
{
public:
Processor(Manager<MatchT>& mgr_):_manager(mgr_) {}
template<int P>
void process();
void doProcess();
private:
Manager<MatchT>& _manager;
template<int P, int... Ps>
struct table : table<P-1,P-1, Ps... > {};
template<int... Ps>
struct table<0, Ps...>
{
static constexpr void(*tns[])() = {process<Ps>...};
};
static table<5> _table;
};
}
#include "processor.C"
processor.C
namespace OM{
#include "MyManager.H" (includes MyManager/MyConfig)
template<typename MatchT>
template<int P>
inline void Processor<MatchT>::process()
{
...
_manager.send(); //this works..
}
template <> template <>
inline void Processor<MyManager<MyConfig> >::process<1>()
{
_manager.send(); //ERROR 1 - see below.
}
//ERROR here:
template<typename MatchT>
void doProcess()
{
Processor<MatchT>::_table::tns[2](); ERROR 3 below.
}
}
compile errors:
1. error: invalid use of incomplete type 'class Manager <MyManager<MyConfig> >'
2. error: declaration of 'class Manager<MyManager<MyConfig> >'
class Manager;
3. error: no type name '_table' in "class Processor<MyManager<MyConfig> >'
I'm not calling this from a specialized function, so I'm not sure
why I'm getting this.
I can move things around a bit to ensure the _manager calls are not within the specialized functions, but I'd rather not if I don't have to.
I played around with this, I think now I get a similar result.
The problem is the template specialisation and forward declaration together. This should be eqvivalent:
template<typename T> struct A;
template<typename T> class B
{
template<int N>
T f();
};
template<typename T> class B<A<T>>
{
A<T> *a;
template<int N>
T f();
};
template<typename T> struct A{ T i=1; };//works
template<>
template<>
int B<A<int>>::f<1>()
{
return a->i + 1;
}
//template<typename T> struct A { T i = 1; };//error
int main()
{
B<A<int>> b;
}
The compilation for templates comes in two stages:
First, it checks syntax and (some) dependence. So, for example if a in B<A<T>> was not a pointer/reference, but the object itself, it could compile, if that B<A<T>> is constructed after A is defined. (worked for me)
So the second is when the compiler inserts the arguments, here, the compiler must know all objects to generate code.
When fully specialising, as above, the compiler is forced to know all types. It already knows, that f function depends on the implementation of A, so it cannot generate the code.
Therefore you have to define A or Manager before the function specialisation.

c++ creating templated objects programmatically

Suppose I want to instantiate many objects that come from a templated class (something like std::bitset) from bitset<1> to bitset<10>.
for (size_t i = 1; i <= 10; ++i) {
std::bitset<i> my_bitset;
// do stuff with it...
}
obviously this won't compile because i is not a literal or a constexpr.
Is there a way to do this? I'm thinking everything template metaprogramming possible in my head but I can't figure this one out. Any pointers appreciated.
It is not possible, as you realized, to use a runtime variable as a template parameter; however should you know the list of values to use at compile-time, then you can indeed have a way to invoke tests for each element of this list.
template <template <size_t> class F>
void run() {}
template <template <size_t> class F, size_t H, size_t... Tail>
void run() { F<H>()(); run<F, Tail...>(); }
Then it is just a matter of defining F:
template <size_t N>
struct BitSetPlay {
void operator()() {
std::bitset<N> b;
b.flip();
std::cout << b.to_ulong() << "\n";
}
};
Putting it altogether:
#include <bitset>
#include <iostream>
template <template <size_t> class F>
void run() {}
template <template <size_t> class F, size_t H, size_t... Tail>
void run() { F<H>()(); run<F, Tail...>(); }
template <size_t N>
struct BitSetPlay {
void operator()() {
std::bitset<N> b;
b.flip();
std::cout << b.to_ulong() << "\n";
}
};
int main() {
run<BitSetPlay, 1u, 2u, 3u, 4u, 5u, 6u, 7u, 8u, 9u, 10u>();
return 0;
}
Note: this assumed a possibly discontiguous list, if it is a range you wish for then you can do without variadic templates by simply keeping track of the bounds.
It's not possible, because templates are a compile-time only concept. You can't use runtime data to declare templated instances.
Template arguments have to be types, or compile-time constants.
Something like (not tested):
template<int N>
struct InstantBS
{
std::bitset<N> bs;
InstantBS<N-1> next;
};
template<>
struct InstantBS<0>
{
};
template struct InstantBS<10>; //instantiate bitset<1> to bitset<10>
UPDATE: Well, I have tested it, and it does not work! The problem is that the members of InstantBS are not implicitly instantiated. And unfortunately, explicit instantiation must occur at namespace level, so you cannot force a explicit instantiation from another explicit instantiation. Unfortunately, template namespaces are not invented yet...
The closest think I can devise is this, doing manual instantation of any member of the bitset you need:
template<int N>
struct InstantBS
{
void DoThings()
{
std::bitset<N> bs;
bs.set();
bs.reset();
bs.flip();
//any other operation you want to instantiate
InstantBS<N-1> next;
next.DoThings();
}
};
template<>
struct InstantBS<0>
{
void DoThings()
{
}
};
template struct InstantBS<10>; //instantiate bitset<1> to bitset<10>, more or less
You can check that the requestet members of the bitsets are actually instantiated:
$ g++ -c test.cpp
$ objdump -t test.o | c++filt | grep bitset
see docs:
The size of a bitset is fixed at compile-time (determined by its template parameter). For a class that also optimizes for space allocation and allows for dynamic resizing, see the bool specialization of vector (vector).

How do I make a class that only compiles when its type has a certain member function?

I have a class named has_f and I want it to only accept template parameters that have a f member function. How would I do that? This is what I tried:
template <typename T, typename = void>
struct has_f : std::false_type {};
template <typename T>
struct has_f<
T,
typename = typename std::enable_if<
typename T::f
>::type
> : std::true_type {};
But I get some cryptic errors. Here is the class I want to use:
struct A
{
void f();
};
How do I do this correctly? Thanks.
From the title of your question I presume that you don't really need a type deriving from true_type or false_type - only to prevent compilation if method f is not present. If that is the case, and if you also require a specific signature (at least in terms of arguments) for that method, in C++11 you can do something like this:
template <typename T>
struct compile_if_has_f
{
static const size_t dummy = sizeof(
std::add_pointer< decltype(((T*)nullptr)->f()) >::type );
};
This is for the case when f() should not accept any arguments. std::add_pointer is only needed if f returns void, because sizeof(void) is illegal.
I +1ed rapptz yesterday for
"possible duplicate of
Check if a class has a member function of a given signature"
and haven't changed my mind.
I suppose it is arguable that this question unpacks to
"A) How to check if a class has a member function of a given signature and
B) How to insist that a class template argumement is a class
as per A)". To B) in this case I would answer with static_assert, since
the questioner apparently isn't interested in enable_if alternatives.
Here is a solution that adapts my answer to
"traits for testing whether func(args) is well-formed and has required return type"
This solution assumes that has_f<T>::value should be true if and only
if exactly the public member void T::f() exists, even if T overloads f or inherits f.
#include <type_traits>
template<typename T>
struct has_f
{
template<typename A>
static constexpr bool test(
decltype(std::declval<A>().f()) *prt) {
return std::is_same<void *,decltype(prt)>::value;
}
template <typename A>
static constexpr bool test(...) {
return false;
}
static const bool value = test<T>(static_cast<void *>(nullptr));
};
// Testing...
struct i_have_f
{
void f();
};
struct i_dont_have_f
{
void f(int);
};
struct i_also_dont_have_f
{
int f();
};
struct i_dont_quite_have_f
{
int f() const;
};
struct i_certainly_dont_have_f
{};
struct i_have_overloaded_f
{
void f();
void f(int);
};
struct i_have_inherited_f : i_have_f
{};
#include <iostream>
template<typename T>
struct must_have_f{
static_assert(has_f<T>::value,"T doesn't have f");
};
int main()
{
must_have_f<i_have_f> t0; (void)t0;
must_have_f<i_have_overloaded_f> t1; (void)t1;
must_have_f<i_have_inherited_f> t2; (void)t2;
must_have_f<i_dont_have_f> t3; (void)t3; // static_assert fails
must_have_f<i_also_dont_have_f> t4; (void)t4; // static_assert fails
must_have_f<i_dont_quite_have_f> t5; (void)t5; // static_assert fails
must_have_f<i_certainly_dont_have_f> t6; (void)t6; // static_assert fails
must_have_f<int> t7; (void)t7; // static_assert fails
return 0;
}
(Built with clang 3.2, gcc 4.7.2/4.8.1)
This toes a fine line between answering your question and providing a solution to your problem but not directly answering your question, but I think you may find this helpful.
For background, check out this question. The author mentions that he didn't like Boost's solution, and I didn't particularly like the one proposed there either. I was writing a quick & dirty serialization library (think python's marshal) where you would call serialize(object, ostream) on an object to serialize it. I realized I wanted this function call to one of four things:
If object is plain old data, just write out the size and raw data
If object is a class that I've created with its own member function (object::serialize), then call that member function
If there's a template specialization for that type, use it.
If none of the above is true, throw a compilation error; the serialize function is being used improperly.
When I code, I try to avoid stuff that is 'tricky' or hard to understand at a glance. I think this solution solves the same problem without using code that must be pondered for hours to understand:
#include <type_traits>
#include <iostream>
#include <vector>
#include <string>
// Template specialization for a POD object
template<typename T>
typename std::enable_if< std::is_pod<T>::value, bool>::type
serial(const T &out, std::ostream &os)
{
os.write((const char*) &out, sizeof(T));
return os.good();
}
// Non POD objects must have a member function 'serialize(std::ostream)'
template<typename T>
typename std::enable_if< ! std::is_pod<T>::value, bool>::type
serial(const T &out, std::ostream &os)
{
return out.serial(os);
}
// Additional specializations here for common container objects
template<typename T>
bool serial(const std::vector<T> &out, std::ostream &os)
{
const size_t vec_size = out.size();
if(!serial(vec_size, os))
return false;
for(size_t i =0; i < out.size(); ++i)
{
if(!serial(out[i], os))
return false;
}
return true;
}
class SomeClass
{
int something;
std::vector<double> some_numbers;
...
bool serial(std::ostream &os)
{
return serial(something, os) && serial(some_numbers, os);
}
};
If you can boil down your needs to a simple set of rules, and can live with a slightly less general solution, I think this method works well.