This is more of a question of how the C++ compiler handles const typeid calls.
Hello! I am trying to make a tuple-style class, configured in such a way that I don't have to rewrite a bunch of the code with specializations.
So this is the general idea:
struct null_type{};
template <typename T1,typename T2=null_type,typename T3=null_type>
class ptestclass
{
private:
template<typename K1,typename K2,typename K3>
class barclass
{
public:
static inline void bar(std::tuple<K1,K2,K3>& vals,K1* otherval1,K2* otherval2,K3* otherval3)
{
Foo(tr1::get<0>(vals),*otherval1);
Foo(tr1::get<1>(vals),*otherval2);
Foo(tr1::get<2>(vals),*otherval3);
}
};
template<typename K1,typename K2>
class barclass<K1,K2,null_type>
{
public:
static inline void bar(std::tuple<K1,K2,null_type>& vals,K1* otherval1,K2* otherval2,null_type* otherval3)
{
Foo(tr1::get<0>(vals),*otherval1);
Foo(tr1::get<1>(vals),*otherval2);
}
};
template<typename K1>
class barclass<K1,null_type,null_type>
{
public:
static inline void bar(std::tuple<K1,null_type,null_type>& vals,K1* otherval1,null_type* otherval2,null_type* otherval3)
{
Foo(tr1::get<0>(vals),*otherval1);
}
};
/*
*Old Bar function...much more readable than bar class, but you cannot partially specialize
*member functions of a class
*
void inline bar(std::tuple<T1,T2,T3> otherval)
{
if (typeid(T1) != typeid(null_type))//constant check hopfully optomized out
{
Foo(vals.get(1),otherval.get(1));
}
if (typeid(T2) != typeid(null_type))//constant check hopfully optomized out
{
Foo(vals.get(2),otherval.get(2));
}
if(typeid(T3) != typeid(null_type))//constant check hopfully optomized out
{
Foo(vals.get(3),otherval.get(3));
}
}
*/
std::tuple<T1,T2,T3> vals;
template<typename K>
void static inline Foo(K& val,K& otherval)
{
//inlineable, short function that is called many (millions) of times per iteration
val += otherval;
}
template<>
void inline Foo<null_type>(null_type& val,null_type& otherval)
{
//inlineable, short function that is called many (millions) of times per iteration
throw "Foo called on null type";
}
public:
ptestclass()
{
printf("made object");
}
void one_iteration(T1* otherval1,T2* otherval2,T3* otherval3,size_t count)
{
for (int i = 0; i < count; ++i)
{
barclass<T1,T2,T3>::bar(vals,otherval1+i,otherval2+i,otherval3+i);
}
}
};
//exposed public class with specialized one_iteration interfaces
template <typename T1,typename T2=null_type,typename T3=null_type>
class testclass : public ptestclass<T1,T2,T3>
{
public:
void one_iteration(T1* otherval1,T1* otherval2,T1* otherval3,size_t count)
{
ptestclass::one_iteration(otherval1,otherval2,otherval3,count);
}
};
template <typename T1>
class testclass<T1,null_type,null_type> : public ptestclass<T1,null_type,null_type>
{
public:
void one_iteration(T1* otherval1,size_t count)
{
ptestclass::one_iteration(otherval1,NULL,NULL,count);
}
};
So my question is is this optimization even possible within C++? If not, it will probably make more sense for me to use an inheritance model on the child nodes rather then a template at this level. However, I am trying to avoid the continual check of the number of types specified and the cost of indirection.
I'm going to start diving into the assembly to see if that is what the compiler does...Just in case this is not standardized behavior, I'm using the Microsoft Visual C++ Compiler 10.0.
I think I misunderstood your question when I put my earlier comment.
Assuming you can use c++11, or you can use boost, you could use something like !std::is_same< T1, null_type >::value /*or boost::is_same...*/ instead of typeid(T1) != typeid(null_type). This uses TMP to resolve to a compile-time constant, which most compilers would have no trouble optimizing away.
This is more of a question of how the C++ compiler handles const typeid calls.
I didn't answer this specific question, but if I understand what you were actually looking for, the above should suffice.
Related
In my application I use a class to flag elements that are inidicated by positive numbers (see code below). The template parameter of class Stamp is usually an unsigned integer. The advantage of flagging with a counter is, that clear() usually executes fast on huge vectors, as one increment of the counter invalidates all flags. Currently, only in my unit tests, I use boolean as template argument. Using boolean comes closest to the naive implementation of flagging numbers. But the increment operator for boolean is deprecated and will soon vanish from the standard and the compiler complains already about deprecation (not knowing that the part it's complaining about wouldn't even be executed in case of boolean). How would you specialize method clear() for the boolean case? I could not get it right, I tried it by just adding the the following definition.
template<>
void Stamp<bool>::clear() {
std::fill(stamped.begin(), stamped.end(), false);
}
Now the compiler complains about multiple definitions of clear(). How is template specialization done right in that case. And what other possibilities do I have to fix this class in modern c++?
template <class T> class Stamp {
private:
std::vector<T> stamped;
T stamp;
public:
Stamp(unsigned int size) {
stamped.resize(size, std::numeric_limits<T>::min());
stamp = std::numeric_limits<T>::min();
}
~Stamp() { }
void clear() {
if (stamp < std::numeric_limits<T>::max()) {
stamp++;
}
else {
std::fill(stamped.begin(), stamped.end(), std::numeric_limits<T>::min());
stamp = std::numeric_limits<T>::min() + 1;
}
}
void unset(unsigned int index) {
assert(index < stamped.size());
stamped[index] = std::numeric_limits<T>::min();
}
void set(unsigned int index) {
assert(index < stamped.size());
stamped[index] = stamp;
}
bool isStamped(unsigned int index) const {
return stamped[index] == stamp;
}
};
EDIT:
Using the answer of #Constructor I could come up with a method specialization by adding another definition of clear() to the header like this:
template<>
inline void Stamp<bool>::clear() {
std::fill(stamped.begin(), stamped.end(), false);
stamp = true;
}
This is kind of ugly but it actually works. Neither compiler nor tests choke on it.
The full (or explicit) function template specialization is not a template. So you should treat it like a normal function.
There are two possibilities not to violate ODR (One Definition Rule) when you are working with functions or methods of classes:
1) place the declaration of the function/method in a header file and its definition in some cpp file:
// Stamp.h
template<>
void Stamp<bool>::clear();
// Stamp.cpp
template<>
void Stamp<bool>::clear()
{
std::fill(stamped.begin(), stamped.end(), false);
stamp = true;
}
2) mark it as inline and place its definition in your header file:
// Stamp.h
template<>
inline void Stamp<bool>::clear()
{
std::fill(stamped.begin(), stamped.end(), false);
stamp = true;
}
Unfortunately, you can't specialize member functions without specializing the whole class. It is a silly language limitation that exists for historical reasons that don't (in my opinion) apply any longer.
Instead of specializing the whole class, you can make Stamp<T> inherit from StampBase<T> which you then specialize.
template <typename T> class StampBase;
template <typename T> class Stamp : public StampBase<T> {
// Code goes here!
void clear() {
StampBase<T>::clear_impl();
// Rest of code.
}
};
template <typename T> class StampBase {
protected:
void clear_impl() { /* T is NOT a bool */ }
};
template <> class StampBase<bool> {
protected:
void clear_impl() { /* T IS a bool */ }
};
I'd like to fill in the store() and launch() methods in the below code. The important detail which captures the spirit of the problem is that the object foo declared in main() no longer exists at the time we call launch(). How can I do this?
#include <cstdio>
#include <cstring>
#include <type_traits>
template<typename T, typename U=
typename std::enable_if<std::is_trivially_copyable<T>::value,T>::type>
struct Launchable {
void launch() { /* some code here */ }
T t;
// other members as needed to support DelayedLauncher
};
class DelayedLauncher {
public:
template<typename T>
void store(const Launchable<T>& t) {
// copy-construct/memcpy t into some storage
}
void launch() const {
// call t.launch(), where t is (a copy of) the last value passed into store()
}
// other members as needed
};
int main() {
DelayedLauncher launcher;
{
Launchable<int> foo;
launcher.store(foo);
}
launcher.launch(); // calls foo.launch()
return 0;
}
Note that if we only had a fixed set of N types to pass into store(), we could achieve the desired functionality by declaring N Launchable<T> fields and N non-template store() methods, one for each type, along with an enum field whose value is use in a switch statement in the launch() method. But I'm looking for an implementation of DelayedLauncher that will not need modification as more Launchable types are added.
using std::function:
class DelayedLauncher {
public:
template<typename T>
void store(const Launchable<T>& t) {
f = [t]() {t.launch();};
}
void launch() const { f(); }
private:
std::function<void()> f;
};
You could give Launchable a base class with a virtual launch() and no template, and store pointers to that base class in Launcher::store.
EDIT: Adapted from #dshin's solution:
struct LaunchableBase {
virtual void launch() = 0;
};
template<typename T, typename U=
typename std::enable_if<std::is_trivially_copyable<T>::value,T>::type>
struct Launchable : public LaunchableBase {
virtual void launch() override { /* some code here */ }
T t;
// other members as needed to support DelayedLauncher
};
class DelayedLauncher {
public:
template<typename T>
void store(const Launchable<T>& t) {
static_assert(sizeof(t) <= sizeof(obj_buffer),
"insufficient obj_buffer size");
static_assert(std::is_trivially_destructible<T>::value,
"leak would occur with current impl");
p = new (obj_buffer) Launchable<T>(t);
}
void launch() const {
p->launch();
}
private:
char obj_buffer[1024]; // static_assert inside store() protects us from overflow
LaunchableBase *p;
};
I believe this variant of Jarod42's solution will avoid dynamic allocation, although I would appreciate if someone could confirm that this will work the way I think it will:
class DelayedLauncher {
public:
template<typename T>
void store(const Launchable<T>& t) {
static_assert(sizeof(t) <= sizeof(obj_buffer),
"insufficient obj_buffer size");
static_assert(std::is_trivially_destructible<T>::value,
"leak would occur with current impl");
auto p = new (obj_buffer) Launchable<T>(t);
auto ref = std::ref(*p);
f = [=]() {ref.get().launch();};
}
void launch() const {
f();
}
private:
char obj_buffer[1024]; // static_assert inside store() protects us from overflow
std::function<void()> f;
};
I believe it should work because the resources I've looked at indicate that std::function implementations typically have a "small capture" optimization, only triggering a dynamic allocation if the total size of the captured data exceeds some threshold.
EDIT: I replaced my code with a version provided by Jarod42 in the comments. The standard guarantees the above implementation will not trigger dynamic allocation.
I need to instantiate a free template function (FTF) within a template class (TC). The FTF takes as a template parameter one of the template parameters of the TC. The TC also holds generic pointers to these FTF's, and these functions are called through the pointers.
The step of taking a pointer to a FTF is not enough to instantiate it, and I receive linker errors from the GCC toolchain. MSDN illustrates FTF specification as so -- however my instantion of the FTF is dependant on a template parameter of my TC, and therefore the FTF instantiation cannot be placed in free scope.
Is this possible ? I am attaching some basic generated code, the issue is in the constructor of the class test_service, where I assign the pointer of a free function into a custom container. I get a linker error telling me the free function cannot be found (uninstantiated). I know that specifying a call to the template function in the class somewhere will produce a instantiation, however I am only going to be making a call via a pointer.
#include "rpc_common.h"
#include <boost/cstdint.hpp>
namespace rubble { namespace rpc {
struct test_service_dummy_tag{};
template<typename T>
class test_service_skel
{
public:
bool Init() {}
bool TearDown() {}
bool test_one(TestRequest,TestResponse){};
private:
};
template<typename T_IMPL>
bool test_service_test_one(T_IMPL & impl,ClientRequest & request)
{
return 0;
}
template<typename T_IMPL=test_service_skel<test_service_dummy_tag> >
class test_service
{
public:
test_service()
{
// uncomment the following two lines and a instantiation will occur.
// ClientRequest cr;
//test_service_test_one<T_IMPL>(m_impl,cr);
m_dispatch_table.SetEntry( Oid("test_one",0),(void *) & test_service_test_one<T_IMPL>);
}
bool Init() { return m_impl.Init(); };
bool TearDown() { return m_impl.TearDown(); };
private:
T_IMPL m_impl;
OidContainer<Oid,void *> m_dispatch_table;
};
} }
EDIT: self-contained minimal version
class test_skel
{
bool test_function()
{
return true;
}
};
template<typename T>
bool test_function()
{
}
template<typename T = test_skel>
class test
{
public:
test()
{
dispatch = (void *) & test_function<T>;
}
void * dispatch;
};
int main()
{
test<> t;
return 0;
}
There is no problem iff you don't use a void*, i.e.: http://www.ideone.com/eRgUG
However, if you insist on storing the pointer in a void*, then you need to take the address using a specific function pointer first and then cast - e.g.
bool (*temp)() = &test_function<T>;
dispatch = reinterpret_cast<void*>(temp); // YUCK
This gives the compiler enough context to generate the address for you.
Ahh - just saw DeadMG's answer, the function to generate the void* is neater...
Your self-contained example wouldn't compile for me with a strange error about overloaded functions, when there is no overloading going on, with MSVC. I did, however, manage to work around it.
class test_skel
{
bool test_function()
{
return true;
}
};
template<typename T> void* to_void_pointer(T t) {
return reinterpret_cast<void*>(t);
}
template<typename T>
bool test_function()
{
return true;
}
template<typename T = test_skel>
class test
{
public:
test()
{
dispatch = to_void_pointer(&test_function<T>);
}
void * dispatch;
};
int main()
{
test<> t;
return 0;
}
This compiles cleanly. I suspect that whatever behaviour you're seeing and I saw is a compiler error.
Suppose I have an autolocker class which looks something like this:
template <T>
class autolocker {
public:
autolocker(T *l) : lock(l) {
lock->lock();
}
~autolocker() {
lock->unlock();
}
private:
autolocker(const autolocker&);
autolocker& operator=(const autolocker&);
private:
T *lock;
};
Obviously the goal is to be able to use this autolocker with anything that has a lock/unlock method without resorting to virtual functions.
Currently, it's simple enough to use like this:
autolocker<some_lock_t> lock(&my_lock); // my_lock is of type "some_lock_t"
but it is illegal to do:
autolocker lock(&my_lock); // this would be ideal
Is there anyway to get template type deduction to play nice with this (keep in my autolocker is non-copyable). Or is it just easiest to just specify the type?
Yes you can use the scope-guard technique
struct autolocker_base {
autolocker_base() { }
protected:
// ensure users can't copy-as it
autolocker_base(autolocker_base const&)
{ }
autolocker_base &operator=(autolocker_base const&)
{ return *this; }
};
template <T>
class autolocker : public autolocker_base {
public:
autolocker(T *l) : lock(l) {
lock->lock();
}
autolocker(const autolocker& o)
:autolocker_base(o), lock(o.lock)
{ o.lock = 0; }
~autolocker() {
if(lock)
lock->unlock();
}
private:
autolocker& operator=(const autolocker&);
private:
mutable T *lock;
};
Then write a function creating the autolocker
template<typename T>
autolocker<T> makelocker(T *l) {
return autolocker<T>(l);
}
typedef autolocker_base const& autolocker_t;
You can then write it like this:
autolocker_t lock = makelocker(&my_lock);
Once the const reference goes out of scope, the destructor is called. It doesn't need to be virtual. At least GCC optimizes this quite well.
Sadly, this means you have to make your locker-object copyable since you need to return it from the maker function. But the old object won't try to unlock twice, because its pointer is set to 0 when it's copied, so it's safe.
Obviously you can't get away with autolocker being a template, because you want to use it as a type, and templates must be instantiated in order to obtain types.
But type-erasure might be used to do what you want. You turn the class template into a class and its constructor into a member template. But then you'd have to dynamically allocate an inner implementation object.
Better, store a pointer to a function that performs the unlock and let that function be an instance of a template chosen by the templatized constructor. Something along these lines:
// Comeau compiles this, but I haven't tested it.
class autolocker {
public:
template< typename T >
autolocker(T *l) : lock_(l), unlock_(&unlock<T>) { l->lock(); }
~autolocker() { unlock_(lock_); }
private:
autolocker(const autolocker&);
autolocker& operator=(const autolocker&);
private:
typedef void (*unlocker_func_)(void*);
void *lock_;
unlocker_func_ unlock_;
template <typename T>
static void unlock(void* lock) { ((T*)lock)->unlock(); }
};
I haven't actually tried this and the syntax might be wrong (I'm not sure how to take the address of a specific function template instance), but I think this should be doable in principle. Maybe someone comes along and fixes what I got wrong.
I like this a lot more than the scope guard, which, for some reason, I never really liked at all.
I think jwismar is correct and what you want is not possible with C++. However, a similar (not direct analogue) construct is possible with C++0x, using several new features (rvalues/moving and auto variable type):
#include <iostream>
template <typename T>
class autolocker_impl
{
public:
autolocker_impl(T *l) : lock(l) {
lock->lock();
}
autolocker_impl (autolocker_impl&& that)
: lock (that.lock)
{
that.lock = 0;
}
~autolocker_impl() {
if (lock)
lock->unlock();
}
private:
autolocker_impl(const autolocker_impl&);
autolocker_impl& operator=(const autolocker_impl&);
private:
T *lock;
};
template <typename T>
autolocker_impl <T>
autolocker (T* lock)
{
return autolocker_impl <T> (lock);
}
struct lock_type
{
void lock ()
{ std::cout << "locked\n"; }
void unlock ()
{ std::cout << "unlocked\n"; }
};
int
main ()
{
lock_type l;
auto x = autolocker (&l);
}
autolocker is a class template, not a class. Your "this would be ideal" is showing something that doesn't make sense in C++.
I am reluctant to say I can't figure this out, but I can't figure this out. I've googled and searched Stack Overflow, and come up empty.
The abstract, and possibly overly vague form of the question is, how can I use the traits-pattern to instantiate member functions? [Update: I used the wrong term here. It should be "policies" rather than "traits." Traits describe existing classes. Policies prescribe synthetic classes.] The question came up while modernizing a set of multivariate function optimizers that I wrote more than 10 years ago.
The optimizers all operate by selecting a straight-line path through the parameter space away from the current best point (the "update"), then finding a better point on that line (the "line search"), then testing for the "done" condition, and if not done, iterating.
There are different methods for doing the update, the line-search, and conceivably for the done test, and other things. Mix and match. Different update formulae require different state-variable data. For example, the LMQN update requires a vector, and the BFGS update requires a matrix. If evaluating gradients is cheap, the line-search should do so. If not, it should use function evaluations only. Some methods require more accurate line-searches than others. Those are just some examples.
The original version instantiates several of the combinations by means of virtual functions. Some traits are selected by setting mode bits that are tested at runtime. Yuck. It would be trivial to define the traits with #define's and the member functions with #ifdef's and macros. But that's so twenty years ago. It bugs me that I cannot figure out a whiz-bang modern way.
If there were only one trait that varied, I could use the curiously recurring template pattern. But I see no way to extend that to arbitrary combinations of traits.
I tried doing it using boost::enable_if, etc.. The specialized state information was easy. I managed to get the functions done, but only by resorting to non-friend external functions that have the this-pointer as a parameter. I never even figured out how to make the functions friends, much less member functions. The compiler (VC++ 2008) always complained that things didn't match. I would yell, "SFINAE, you moron!" but the moron is probably me.
Perhaps tag-dispatch is the key. I haven't gotten very deeply into that.
Surely it's possible, right? If so, what is best practice?
UPDATE: Here's another try at explaining it. I want the user to be able to fill out an order (manifest) for a custom optimizer, something like ordering off of a Chinese menu - one from column A, one from column B, etc.. Waiter, from column A (updaters), I'll have the BFGS update with Cholesky-decompositon sauce. From column B (line-searchers), I'll have the cubic interpolation line-search with an eta of 0.4 and a rho of 1e-4, please. Etc...
UPDATE: Okay, okay. Here's the playing-around that I've done. I offer it reluctantly, because I suspect it's a completely wrong-headed approach. It runs okay under vc++ 2008.
#include <boost/utility.hpp>
#include <boost/type_traits/integral_constant.hpp>
namespace dj {
struct CBFGS {
void bar() {printf("CBFGS::bar %d\n", data);}
CBFGS(): data(1234){}
int data;
};
template<class T>
struct is_CBFGS: boost::false_type{};
template<>
struct is_CBFGS<CBFGS>: boost::true_type{};
struct LMQN {LMQN(): data(54.321){}
void bar() {printf("LMQN::bar %lf\n", data);}
double data;
};
template<class T>
struct is_LMQN: boost::false_type{};
template<>
struct is_LMQN<LMQN> : boost::true_type{};
// "Order form"
struct default_optimizer_traits {
typedef CBFGS update_type; // Selection from column A - updaters
};
template<class traits> class Optimizer;
template<class traits>
void foo(typename boost::enable_if<is_LMQN<typename traits::update_type>,
Optimizer<traits> >::type& self)
{
printf(" LMQN %lf\n", self.data);
}
template<class traits>
void foo(typename boost::enable_if<is_CBFGS<typename traits::update_type>,
Optimizer<traits> >::type& self)
{
printf("CBFGS %d\n", self.data);
}
template<class traits = default_optimizer_traits>
class Optimizer{
friend typename traits::update_type;
//friend void dj::foo<traits>(typename Optimizer<traits> & self); // How?
public:
//void foo(void); // How???
void foo() {
dj::foo<traits>(*this);
}
void bar() {
data.bar();
}
//protected: // How?
typedef typename traits::update_type update_type;
update_type data;
};
} // namespace dj
int main() {
dj::Optimizer<> opt;
opt.foo();
opt.bar();
std::getchar();
return 0;
}
A simple solution might be to just use tag-based forwarding, e.g. something like this:
template<class traits>
void foo(Optimizer<traits>& self, const LMQN&) {
printf(" LMQN %lf\n", self.data.data);
}
template<class traits>
void foo(Optimizer<traits>& self, const CBFGS&) {
printf("CBFGS %d\n", self.data.data);
}
template<class traits = default_optimizer_traits>
class Optimizer {
friend class traits::update_type;
friend void dj::foo<traits>(Optimizer<traits>& self,
const typename traits::update_type&);
public:
void foo() {
dj::foo<traits>(*this, typename traits::update_type());
}
void bar() {
data.bar();
}
protected:
typedef typename traits::update_type update_type;
update_type data;
};
Or if you want to conveniently group several functions together for different traits, maybe something like this:
template<class traits, class updater=typename traits::update_type>
struct OptimizerImpl;
template<class traits>
struct OptimizerImpl<traits, LMQN> {
static void foo(Optimizer<traits>& self) {
printf(" LMQN %lf\n", self.data.data);
}
};
template<class traits>
struct OptimizerImpl<traits, CBFGS> {
static void foo(Optimizer<traits>& self) {
printf("CBFGS %d\n", self.data.data);
}
};
template<class traits = default_optimizer_traits>
class Optimizer{
friend class traits::update_type;
friend struct OptimizerImpl<traits>;
public:
void foo() {
OptimizerImpl<traits>::foo(*this);
}
// ...
};
I think template specialization is a step in the right direction. This doesn't work with functions so I switched to classes. I changed it so it modifies the data. I'm not so sold on the protected members and making friends. Protected members without inheritance is a smell. Make it public or provide accessors and make it private.
template <typename>
struct foo;
template <>
struct foo<LMQN>
{
template <typename OptimizerType>
void func(OptimizerType& that)
{
printf(" LMQN %lf\n", that.data.data);
that.data.data = 3.14;
}
};
template <>
struct foo<CBFGS>
{
template <typename OptimizerType>
void func(OptimizerType& that)
{
printf(" CBFGS %lf\n", that.data.data);
}
};
template<class traits = default_optimizer_traits>
class Optimizer{
public:
typedef typename traits::update_type update_type;
void foo() {
dj::foo<typename traits::update_type>().func(*this);
}
void bar() {
data.bar();
}
update_type data;
};
It would be trivial to define the traits with #define's and the member functions with #ifdef's and macros. But that's so twenty years ago.
Although it may be worth learning new methods, macros are often the simplest way to do things and shouldn't be discarded as a tool just because they're "old". If you look at the MPL in boost and the book on TMP you'll find much use of the preprocessor.
Here's what I (the OP) came up with. Can you make it cooler?
The main Optimizer template class inherits policy-implementation classes. It gives those classes access to the Optimizer's protected members that they require. Another Optimizer template class splits the manifest into its constituent parts and instantiates the main Optimizer template.
#include <iostream>
#include <cstdio>
using std::cout;
using std::endl;
namespace dj {
// An updater.
struct CBFGS {
CBFGS(int &protect_)
: protect(protect_)
{}
void update () {
cout << "CBFGS " << protect << endl;
}
// Peek at optimizer's protected data
int &protect;
};
// Another updater
struct LMQN {
LMQN(int &protect_)
: protect(protect_)
{}
void update () {
cout << "LMQN " << protect << endl;
}
// Peek at optimizer's protected data
int &protect;
};
// A line-searcher
struct cubic_line_search {
cubic_line_search (int &protect2_)
: protect2(protect2_)
{}
void line_search() {
cout << "cubic_line_search " << protect2 << endl;
}
// Peek at optimizer's protected data
int &protect2;
};
struct default_search_policies {
typedef CBFGS update_type;
typedef cubic_line_search line_search_type;
};
template<class Update, class LineSearch>
class Opt_base: Update, LineSearch
{
public:
Opt_base()
: protect(987654321)
, protect2(123456789)
, Update(protect)
, LineSearch(protect2)
{}
void minimize() {
update();
line_search();
}
protected:
int protect;
int protect2;
};
template<class Search_Policies=default_search_policies>
class Optimizer:
public Opt_base<typename Search_Policies::update_type
, typename Search_Policies::line_search_type
>
{};
} // namespace dj
int main() {
dj::Optimizer<> opt; // Use default search policies
opt.minimize();
struct my_search_policies {
typedef dj::LMQN update_type;
typedef dj::cubic_line_search line_search_type;
};
dj::Optimizer<my_search_policies> opt2;
opt2.minimize();
std::getchar();
return 0;
}
Your use of enable_if is somewhat strange. I've seen it used it only 2 ways:
in place of the return type
as a supplementary parameter (defaulted)
Using it for a real parameter might cause the havoc.
Anyway, it's definitely possible to use it for member functions:
template<class traits = default_optimizer_traits>
class Optimizer{
typedef typename traits::update_type update_type;
public:
typename boost::enable_if< is_LQMN<update_type> >::type
foo()
{
// printf is unsafe, prefer the C++ way ;)
std::cout << "LQMN: " << data << std::endl;
}
typename boost::enable_if< is_CBFGS<update_type> >::type
foo()
{
std::cout << "CBFGS: " << data << std::endl;
}
private:
update_type data;
};
Note that by default enable_if returns void, which is eminently suitable as a return type in most cases. The "parameter" syntax is normally reserved for the constructor cases, because you don't have a return type at your disposal then, but in general prefer to use the return type so that it does not meddle with overload resolution.
EDIT:
The previous solution does not work, as noted in the comments. I could not find any alternative using enable_if, only the "simple" overload way:
namespace detail
{
void foo_impl(const LMQN& data)
{
std::cout << "LMQN: " << data.data << std::endl;
}
void foo_impl(const CBFGS& data)
{
std::cout << "CBFGS: " << data.data << std::endl;
}
} // namespace detail
template<class traits = default_optimizer_traits>
class Optimizer{
typedef typename traits::update_type update_type;
public:
void foo() { detail::foo_impl(data); }
private:
update_type data;
};
It's not enable_if but it does the job without exposing Optimizer internals to everyone. KISS ?