I'm using boost::multi_index_container and am trying to get a modify operation working. My modification routine looks like this (roughly), using a function inner class:
void FooContainer::modifyAttribute(string key, int newValue) {
struct ModifyFunc {
int val;
ModifyFunc(int val): val(val) {}
void operator()(Foo &f) {
foo.val = val;
}
};
StorageContainer::index<keyTag>::type &idx = mContainer.get<keyTag>();
StorageContainer::index<keyTag>::type::iterator iter = idx.find(key);
idx.modify(iter, ModifyFunc(newValue));
}
When I try to compile this, I get a multi-page spew of compiler error like this (most of it omitted):
FooContainer.cpp:##: error: no matching function for call to [...]::modify([...]&, FooContainer::modifyAttribute(string,int)::ModifyFunc)’
What's wrong with this invocation and how can I make it work?
The problem is that function inner classes aren't recognized by the compiler as a valid typename for template parameters; it isn't obvious, but the multi_index_container::index<T>::type::modify method uses the type of the modify parameter as a template argument which is a detail normally hidden from view. However, look at its declaration in, for example, boost/multi_index/hashed_index.hpp:
template<typename Modifier>
bool modify(iterator position,Modifier mod)
The easy fix is to make the ModifyFunc struct not a function inner class; trivially, make it inner to FooContainer rather than to the FooContainer::modifyAttribute method. Of course, this also means that you can reuse the ModifyFunc class elsewhere, if it turns out you need it in more than one place.
Related
I’m trying to use static_assert to force something to fail. If you try to instantiate a specific templated function in a specific way I want to generate a complier error. I could make it work, but it was really ugly. Is there an easier way to do this?
This was my first attempt. This did not work at all. It always generates an error, even if no one tries to use this function.
template< class T >
void marshal(std::string name, T *value)
{
static_assert(false, "You cannot marshal a pointer.");
}
Here’s my second attempt. It actually works. If you don’t call this, you get no error. If you do call this, you get a very readable error message that points to this line and points to the code that tried to instantiate it.
template< class T >
void marshal(std::string name, T *value)
{
static_assert(std::is_pod<T>::value && !std::is_pod<T>::value, "You cannot marshal a pointer.");
}
The problem is that this code is ugly at best. It looks like a hack. I’m afraid the next time I change the optimization level, upgrade my compiler, sneeze, etc, the compiler will realize that this second case is the same as the first, and they will both stop working.
Is there a better way to do what I’m trying to do?
Here’s some context. I want to have several different versions of marshal() which work for different input types. I want one version that uses a template as the default case. I want another one that specifically disallows any pointers except char *.
void marshal(std::string name, std::string)
{
std::cout<<name<<" is a std::string type."<<std::endl;
}
void marshal(std::string name, char *string)
{
marshal(name, std::string(string));
}
void marshal(std::string name, char const *string)
{
marshal(name, std::string(string));
}
template< class T >
void marshal(std::string name, T value)
{
typedef typename std::enable_if<std::is_pod<T>::value>::type OnlyAllowPOD;
std::cout<<name<<" is a POD type."<<std::endl;
}
template< class T >
void marshal(std::string name, T *value)
{
static_assert(false, "You cannot marshal a pointer.");
}
int main (int argc, char **argv)
{
marshal(“should be pod”, argc);
marshal(“should fail to compile”, argv);
marshal(“should fail to compile”, &argc);
marshal(“should be std::string”, argv[0]);
}
There is no way to do this. You might be able to make it work on your compiler, but the resulting program is ill formed no diagnostic required.
Use =delete.
template< class T >
void marshal(std::string name, T *value) = delete;
What you are trying to do is doomed to be ill-formed (even your workaround can fail) according to [temp.res]/8 (emphasis mine):
Knowing which names are type names allows the syntax of every template
to be checked. The program is ill-formed, no diagnostic required, if:
- no valid specialization can be generated for a template or a substatement of a constexpr if statement within a template and the
template is not instantiated, or (...)
Relying on a contradiction is not the best indeed, but there's a simpler way:
template <class...>
struct False : std::bool_constant<false> { };
template <class T>
void bang() {
static_assert(False<T>{}, "bang!");
}
Why does this not fall under the "no valid specialization" case?
Well, because you can actually make a valid specialization, with that second half of the code:
template <>
struct False<int> : std::bool_constant<true> { };
int main() {
bang<int>(); // No "bang"!
}
Of course, no one is actually going to specialize False to break your assertions in real code, but it is possible :)
I don't understand why you have template< class T > void marshal(std::string name, T *value) in the first place. This should just be a static_assert in the primary template.
That is, you should change the definition of your primary template to
template< class T >
void marshal(std::string name, T value)
{
static_assert(std::is_pod<T>::value);
static_assert(!std::is_pointer<T>::value);
std::cout<<name<<" is a POD type."<<std::endl;
}
I am implementing a hashtable, and I have written the following (fragment of a) class definition:
template <typename KEY, typename VAL>
class ExtendibleHashTable {
/* Main hash function used. Initially, the identity function. */
size_t hash(KEY key) {
return key;
}
I want to further add a public method, that allows one to set a custom hash function. I do know about function pointers, so I tried something like this (underneath, in the same class definition):
/* Set new hash. */
void set_hash(size_t new_hash(KEY)) {
this -> hash = new_hash;
}
However, this does not compile.
Can you tell me the best way to achieve this effect? I have looked at the <functional> header but it doesn't seem to be the answer I need (or maybe I haven't understood its purpose).
You cannot replace member functions dynamically in C++. Nor can you dynamically add member functions.
You can, however, have a class that contains function pointers or std:: function objects that you can change at run-time. So, you could for example do something like this:
class ExtendibleHashTable {
private:
std::function<size_t (KEY)> m_hash_func;
public:
size_t hash(KEY key) {
if (m_hash_func) {
return m_hash_func(key);
}
return key;
}
void set_hash(const std::function<size_t (KEY)>& func) {
m_hash_func = func;
}
};
In the above, the hash function will by default just return key if no specific function has been set. But, if set_hash has been called with an appropriate hash function (free standing function, function object or lambda), then it will instead call that function and return its result.
I am looking to move some of the code of within a template method to a non-template method in order to decrease the binary size.
There is a template class called 'Target', as illustrated below
template<TargetType K, typename V = plat_target_handle_t>
class Target
{
.............
..............
};
TargetType is an enum data type.
template<>
template< TargetType T>
std::vector<Target<T> >
Target<TARGET_TYPE_X>::getChildren(const TargetState i_state) const
{
std::vector<Target<T> > l_children;
for ( int i=0; i < elements_in_some_list ; ++i)
{
/*If the current entry in some_list match my critera, add to the l_children */
}
}
TargetType is an enum data type and TARGET_TYPE_X is one of the enum values.
I want to move all the logic to select the children to a global method, lets say getChildrenHelper.
getChildrenHelper is declared as below.
void getGhildrenHelper(const TargetType i_targetType,
const TargetState i_targetstate,
std::vector<Target<TARGET_TYPE_ALL>> & io_children);
And then the getChildren method would eventually look like
template<>
template< TargetType T>
std::vector<Target<T> >
Target<TARGET_TYPE_X>::getChildren(const TargetState i_state) const
{
std::vector<Target<T> > l_children;
childHelper(T,i_state,l_children);
return l_children;
}
My guess is this cannot be done, though the native compiler that I am working with did not through an error.
However there is another existing code where the similar concept is working perfectly fine
template< TargetType K >
inline ReturnCode putParam(const Target<K>& i_target,
const RingID i_ringID,
const RingMode i_ringMode)
{
ReturnCode l_rc = FAPI2_RC_SUCCESS;
// Find the string in the SEEPROM
l_rc = findInImageAndApply(i_target, i_ringID, i_ringMode);
return l_rc;
}
fapi2::ReturnCode findImageAndApply(
const fapi2::Target<fapi2::TARGET_TYPE_ALL>& i_target,
const RingID i_ringID,
const fapi2::RingMode i_ringMode)
{
................
................
}
It is quite common for template functions to invoke ordinary, non-template functions in order to execute a large chunk of code that does not need or use any template parameters. This is a common technique for avoiding template-generated code bloat.
In your case, TargetType appears is a template parameter, and there is no such class. As such:
void getGhildrenHelper(const TargetType i_targetType,
const TargetState i_targetstate,
std::vector<Target<TARGET_TYPE_ALL>> & io_children);
that by itself should not compile, since TargetType appears to be a template parameter, and not a class name, based on the code in your template specialization.
But, your code might be ambiguous, here. In any case, if neither TargetType and TargetState, nor Target<TARGET_TYPE_ALL> are template parameters, this would make this an ordinary function, and it can certainly be invoked from a template function, with matching parameters.
A template function can do anything that an ordinary function does, including calling other functions, or using other templates. The requirements are the same as for any other function: matching function parameter types, etc...
Suppose I have the following core class:
class Core {
public:
template<typename T>
void accept(T object);
}
I now want to be able to write methods like this:
void handle(int par);
and register them somewhere during linking/compiling stage and call the correct method registered for some typename in the Core.accept(T) method. For example calling
Core.accept(5) would hand 5 over to the handle(int) function after it is somehow registered. Something like this (not compilable example):
template<typename T>
void Core::accept(T par) {
// constexpr std::map<std::type_info, Function> type_func_mapping;
auto it = type_func_mapping.get(typeid(T)); // Should be constexpr
static_assert (it != type_func_mapping.end(), "No handler found for typename " + typeid(T).name())
auto function = *it; // Also constexpr
function(par);
}
Are there any problems with this approach/does exist a better one?
Note: I want to be able to extract the sources of class Core in a way that I can store them in a read-only header/source file and don't even have to touch them again.
You could use pointer to functions to store the registered function.
static void (*reg_func)(args);
static void register(void (*func)(args)){
reg_func = func;
}
//registration part
register(handle);
//function call inside accept,use can use some sanity checks also
reg_func(5 or whatever)
With this you don't have to touch your core class or even the file containing the core class. You can define the handle function in some other file but take care of visibility mode of handle function. Your handle function will register itself and then accept can call the registered function.
Hi I have a problem to compile my class in XCode, gcc(Apple LLVM compiler 3.0)
I wrote class ContextSchedule it means class which encapsulates list of other class member functions and have no problem to compile it under MSVC++ 2005.
template<class T>
class C_ContextScheduler
{
public:
typedef void (T::*T_EventFunc)();
typedef std::map<u64, T_EventFunc> T_EventMap;
public:
//# c-tor
C_ContextScheduler(T & context) : m_Context(context), m_currentTick(0) {};
//# Schedule
//# funcPtr - pointer to function of class T
//# dellayTime in milliseconds - after dellayTime from now will be funcPtr called
void Schedule(T_EventFunc funcPtr, u32 dellayTime)
{
u64 callingTime = m_currentTick + dellayTime;
std::pair<int, bool> res = m_eventMap.insert(T_EventMap::value_type(callingTime, funcPtr));
SC_ASSERT(res.second);
} ...
Any ideas? Want preserve template way of this solution, thnx.
When the compiler compiles this template, T is not yet known. Therefore the exact type of T_EventFunc and T_EventMap is also not yet known and that compiler doesn't know that T_EventMap::value_type will end up being a type. To make this clear, use the typename keyword:
... = m_eventMap.insert(typename T_EventMap::value_type(callingTime, funcPtr));
Since you don't supply the error you are getting, we can only guess. And my guess is that the result of your insert-call is not correct.
According to this refernce, the return value of std::map::insert is std::pair<iterator, bool>. Are you sure the iterator is an int?