I'm wondering what's the proper syntax for calling template method given as:
struct print_ch {
print_ch(char const& ch) : m_ch(ch) { }
~print_ch() { }
template<typename T>
void operator()() {
std::cout << static_cast<T>(m_ch) << std::endl;
}
private:
char m_ch;
};
I came up with sth like this:
print_ch printer('c');
printer.operator()<int>();
And it seems to work (GCC 4.5), but when I use it inside another templated method, e.g.:
struct printer {
typedef int print_type;
template<typename T_functor>
static void print(T_functor& fnct) {
fnct.operator()<print_type>();
}
};
Compilation fails with error: expected primary-expression before '>' token. Any idea to get it right? Thanks in advance.
You have to tell the compiler explicitly that the operator() of the templated fnct is itself a template:
fnct.template operator()<print_type>();
If you don't specify this with the template keyword the compiler will assume that operator() is just a normal method, not a template.
Since T_functor is itself a template, the compiler (or parser) assumes to know nothing about it's members, so you have to explicetly tell it you are calling a template methode using:
fnct.template operator()<print_type>();
Related
I have a need to implement 2 functions inside a templated class, where both functions do similar things, but not everything is the same. My proposed solution was to use if constexpr on a single template function, and then have an alias for each function:
template <typename T>
class MyClass
{
private:
template <bool test>
void TestFunc()
{
if constexpr(test)
{
// Do something
}
else
{
// Do other stuff
}
}
public:
?????? TestTrue = TestFunc<true>;
?????? TestFalse = TestFunc<false>;
}
I'm trying to figure out what should go where the question marks are, so far using, auto and const auto have not worked. I want the user to be able to call TestTrue() and TestFalse() directly from an object of the class directly.
You could do:
void TestTrue() { TestFunc<true>(); }
void TestFalse() { TestFunc<false>(); }
I don't think there's a better way.
For completeness, here's the ugly way.
As mentioned in the comments, TestFunc is a member function, not a type, so if you want to reference an explicit specialization of it, you'll need to use a member function pointer. In our case, these will be pointers of the following type.
using MemberTestFunction = void (MyClass::*)();
We can then acquire pointers to the true and false specialization of TestFunc like so:
template <typename T>
class MyClass
{
// ...
constexpr static MemberTestFunction TestTrue = &MyClass::TestFunc<true>;
constexpr static MemberTestFunction TestFalse = &MyClass::TestFunc<false>;
};
If you're not familiar with pointers to member functions, the syntax for calling TestTrue and TestFalse may look rather bizarre. If you're inside a member function, you can invoke these functions either by using the ->* operator, or by using std::invoke (C++17) from <functional>:
template <typename T>
class MyClass
{
// ...
void foo() {
// Direct call with pointer.
(this->*TestTrue)();
// Call using std::invoke.
std::invoke(TestTrue, this);
}
};
Alternatively, outside of MyClass, these calls would look like the following.
MyClass<nullptr_t> x;
// Using type deducation.
(x.*decltype(x)::TestTrue)();
// Using fully qualified name.
(x.*MyClass<nullptr_t>::TestTrue)();
// Using std::invoke (with type deducation).
std::invoke(decltype(x)::TestTrue, x);
It goes without saying this this is a needlessly obscure way of accomplishing any otherwise simple task. I would not advocate using this technique over creating new functions (as HolyBlackCat suggested) or simply naming TestFunc<true>() and TestFunc<false>() explicitly at the call site.
Transform function TestFunc to functor:
#include <iostream>
template <typename T>
class MyClass
{
private:
template <bool test>
struct TestFunc
{
void operator()() {
if constexpr(test)
{
std::cout << "TestTrue\n";
}
else
{
std::cout << "TestFalse\n";
}
}
};
public:
TestFunc<true> TestTrue;
TestFunc<false> TestFalse;
};
int main()
{
MyClass<int> myClass;
myClass.TestTrue();
myClass.TestFalse();
}
Let us assume we have a function template which is implemented in the cpp file with help of explicit instantiation like this:
function.h
template<typename T> void function(T val);
function.cpp
#include "function.h"
template<typename T> void function(T val) { /* do something */ }
template void function<double>(double val);
We are now able to call the function in a main file that includes function.h like this:
double val = 1.0;
function(val);
Let us further assume we have a class which is implemented like this:
data.h
class Data
{
private:
double mVal;
public:
Data(double val) { mVal = val; }
operator double () { return mVal; }
};
The following code results in the linker error LNK2019: unresolved external (Visual Studio 2010):
Data a(1.0);
function(a);
We could use one of the following expressions to supply a to function()
function<double>(a);
function(double(a));
...
but why is it not possible to just call function(a)? Does there exist any other solution to achieve that without explicitly instantiating function() with type Data?
why is it not possible to just call function(a)?
It is. You're calling it. But remember that function is declared as:
template<typename T> void function(T val);
so template deduction will deduce function<Data>. The template deduction doesn't know that elsewhere in the code you only have a definition for function<double> - it just does deduction. And function<Data> doesn't have a definition, so it fails to link.
Performing the explicit cast yourself (either function<double>(a) or function(static_cast<double>(a))) would be the best solution in my opinion. Explicit is nice. You could additionally write a separate function with all the overloads you actually support and just forward to the function template:
void fwd_function(double v) { function(v); }
void fwd_function(foo v) { function(v); }
void fwd_function(bar v) { function(v); }
fwd_function(a); // now we call function<double> because fwd_function(double )
// is the what we're actually calling
It is not possible to call function(a), because then T will be of type Data, and not double, even though it has that conversion operator. And because you are not explicitly defining it in the cpp file, you get a linker error.
Here are some solutions you could use:
//Call operator double() explicitly
function(a.operator double());
//Specify T
function<double>(a);
//Casting
function(static_cast<double>(a));
I'm in the process of refactoring a large class -- let's call it Big -- that has a huge amount of copy-paste code. Much of this copy-paste code exists in switch cases where only the types involved end up being different. The code is switching based on an enum member variable of the class whose value is known only at runtime.
My attempt to fix this involves having a Dispatcher class that looks up appropriately typed functions via a static function called lookup(). The functions that do the actual work are always called go() and have to be defined in a wrapper class template (whose sole parameter is the runtime enum value currently being switched on). The go() functions may or may not be template functions themselves.
Here is a distilled version of the code. My apologies for the length, but this was as short as I could get it without losing important context.
#include <cassert>
class Big
{
public:
enum RuntimeValue { a, b };
Big(RuntimeValue rv) : _rv(rv) { }
bool equals(int i1, int i2)
{
return Dispatcher<Equals, bool(int, int)>::lookup(_rv)(i1, i2);
}
template<typename T>
bool isConvertibleTo(int i)
{
return Dispatcher<IsConvertibleTo, bool(int)>::lookup<T>(_rv)(i);
}
private:
template<RuntimeValue RV>
struct Equals
{
static bool go(int i1, int i2)
{
// Pretend that this is some complicated code that relies on RV
// being a compile-time constant.
return i1 == i2;
}
};
template<RuntimeValue RV>
struct IsConvertibleTo
{
template<typename T>
static bool go(int i)
{
// Pretend that this is some complicated code that relies on RV
// being a compile-time constant.
return static_cast<T>(i) == i;
}
};
template<template<RuntimeValue> class FunctionWrapper, typename Function>
struct Dispatcher
{
static Function * lookup(RuntimeValue rv)
{
switch (rv)
{
case a: return &FunctionWrapper<a>::go;
case b: return &FunctionWrapper<b>::go;
default: assert(false); return 0;
}
}
template<typename T>
static Function * lookup(RuntimeValue rv)
{
switch (rv)
{
case a: return &FunctionWrapper<a>::go<T>;
case b: return &FunctionWrapper<b>::go<T>;
default: assert(false); return 0;
}
}
// And so on as needed...
template<typename T1, typename T2>
static Function * lookup(RuntimeValue rv);
};
RuntimeValue _rv;
};
int main()
{
Big big(Big::a);
assert(big.equals(3, 3));
assert(big.isConvertibleTo<char>(123));
}
This mostly works, except that:
It builds and works fine under Visual C++ 9 (2008), but under GCC 4.8 it results in compilation errors in the function-template overload of lookup().
It requires that a new function-template overload of lookup() be written for every new number of function template parameters that we want to support in go().
It's cumbersome and confusing to use.
Here are the errors that occur under GCC:
Big.cpp: In static member function 'static Function* Big::Dispatcher<FunctionWrapper, Function>::lookup(Big::RuntimeValue)':
Big.cpp(66,65) : error: expected primary-expression before '>' token
case a: return &FunctionWrapper<a>::go<T>;
^
Big.cpp(66,66) : error: expected primary-expression before ';' token
case a: return &FunctionWrapper<a>::go<T>;
^
Big.cpp(67,65) : error: expected primary-expression before '>' token
case b: return &FunctionWrapper<b>::go<T>;
^
Big.cpp(67,66) : error: expected primary-expression before ';' token
case b: return &FunctionWrapper<b>::go<T>;
^
My question is twofold:
Why is this failing to build under GCC, and how do I fix it?
Is there a better (i.e., less cumbersome and confusing) way to do this?
The code has to be compilable under Visual C++ 9 (2008), so I can't use anything C++11-specific.
Since go is a dependent name of a template, you need to use the template disambiguator:
case a: return &FunctionWrapper<a>::template go<T>;
// ^^^^^^^^
case b: return &FunctionWrapper<b>::template go<T>;
// ^^^^^^^^
This tells the compiler to parse what follows the scope resolution operator (::) as the name of a template, and the subsequent angular brackets as delimiters for the template arguments.
Why is this failing to build under GCC, and how do I fix it?
Because GCC is conforming to the Standard, and performs two-phase name lookup, while MSVC delays name lookup until instantiation time and, therefore, knows that go is the name of a template.
Before instantiation this information is not available, because it is impossible to know what T is, and the primary template could be specialized for a given T so that go is not the name of a member function template, but rather of a data member.
This said, I expect MSVC to support the template disambiguator anyway, so adding it should make your program compile both on GCC/Clang/whatever-conforms-to-the-Standard and on MSVC.
I recently wrote a command dispatcher:
#include <map>
// because std::invoke is not in this compiler version.
#define CALL_MEMBER_FN(object,ptrToMember) ((object).*(ptrToMember))
template <class MyType, class cmd_type, class ret_type, typename... Args>
class CommandDispatcher {
typedef ret_type (MyType::*CommandFunction)(Args... args);
public:
// create using static/existing map
CommandDispatcher(std::map<cmd_type, CommandFunction>& cmd_map) : _command_table(cmd_map) {}
ret_type operator()(MyType& my_obj, cmd_type cmd, Args... args)
{
int retval = 0;
if (_command_table.find(cmd) == _command_table.end()) {
std::cerr << "No command implementation found: " << cmd << endl;
return -EINVAL;
}
return CALL_MEMBER_FN(my_obj, _command_table[cmd])(args...);
}
private:
std::map<cmd_type, CommandFunction>& _command_table;
};
Using it looks like:
class MyClass {
public:
MyClass() : _dispatcher(_command_map) {}
private:
static std::map<int, CommandFunction> _command_map;
CommandDispatcher<MyClass, int, int, const char*, int> _dispatcher;
};
And in cpp:
std::map<int, CommandFunction> MyClass::_command_map{
{E_CMD1, &MyClass::Cmd1},
{E_CMD2, &MyClass::Cmd2},
};
I am working with legacy code of a template that is based on
template<class keyType, class dType> Foo Bar(const dType val)
Somewhere in that code is a place where someone made a debug function like this:
virtual void getDebugStr01(int db_id, OFCString & db_str)
{
//OFCStringStream ss;
if(db_id==0)
{
map<keyType, dType>::iterator it = m_stateData.begin();
for(;it!=m_stateData.end();it++)
{
(it->second).getDebugStr01(db_str);
}
}
}
Now, I would need to use the template class with a float. Is there anyway to do this?
Currently I get a:
error C2228: left of '.getDebugStr01' must have class/struct/union
getDebugStr01() should be a member of a class/struct. virtual methods cannot be stand alone.
You can do something like,
Foo Bar (const float f)
{
...
}
I'm trying to create a template class to insulate the users from a data type. I would have preferred to use an adapter class, but the function signatures needed to change requiring a template.
In the code sample below(not the actual project just a simplified version to illustrate the problem), while in the main routine I'm able to use the ob_traits interface. But when I attempt to create the templated StructWrapper which uses the ob_traits as a base class, I get errors and gcc doesn't recognize the IntAdapter class created. This compiles on MSVC 8.0 but fails on gcc 4.1.2 20070626 ( Red hat 4.1.2-14)
So two questions first, do you understand why the compile fails with the errors specified below?
Second, any suggestions on how to implement this concept in a more simple manner?
#include <iostream>
template <typename T >
struct ob_traits
{
ob_traits( T& param ) { value = param; };
T value;
};
struct GeneralStructure
{
int a;
GeneralStructure(int param):a(param){}
};
struct DifferentStructure
{
GeneralStructure hidden;
DifferentStructure( int param ):hidden(param){};
}
;
/*template< typename T > struct ob_traits
{
};
*/
template<> struct ob_traits< GeneralStructure >
{
struct IntAdapter
{
IntAdapter( GeneralStructure& valueParam ):value(valueParam){}
GeneralStructure value;
int& getValue() { return value.a; };
};
};
template<> struct ob_traits< DifferentStructure >
{
struct IntAdapter
{
IntAdapter( DifferentStructure& valueParam):value( valueParam ){}
DifferentStructure value;
int& getValue( ){ return value.hidden.a; };
};
void dump()
{
DifferentStructure testLocal(44);
IntAdapter local( testLocal );
std::cout << local.getValue()<<std::endl;
}
};
template <typename T > struct StructWrapper:public ob_traits< T >
{
StructWrapper(){};
/*main.cpp:60: error: 'IntAdapter' was not declared in this scope
main.cpp:60: error: expected `;' before 'inner'
main.cpp:60: error: 'inner' was not declared in this scope
*/
void dumpOuter(const T& tempParam) { IntAdapter inner(tempParam); inner.dump(); };
/*
main.cpp: In member function 'void StructWrapper<T>::dumpOuterFailsAsWell(const T&)':
main.cpp:66: error: expected `;' before 'inner'
main.cpp:66: error: 'inner' was not declared in this scope
*/
void dumpOuterFailsAsWell(const T& tempParam) { ob_traits<T>::IntAdapter inner(tempParam); inner.dump(); };
};
int main(int argc, char* argv[])
{
GeneralStructure dummyGeneral(22);
ob_traits<struct GeneralStructure >::IntAdapter test(dummyGeneral);
DifferentStructure dummyDifferent(33);
ob_traits<struct DifferentStructure >::IntAdapter test2(dummyDifferent);
std::cout << "GeneralStructure: "<<test.getValue()<<std::endl;
std::cout << "DifferentStructure: "<<test2.getValue()<<std::endl;
ob_traits<struct DifferentStructure > test3;
test3.dump();
std::cout << "Test Templated\n";
return 0;
}
dumpOuter fails because IntAdapter needs to be qualified (as in the referenced question). dumpOuterFailsAsWell fails because GCC does parsing of this code,even though it's not complete, and so it needs to know it's a type that you mean:
void dumpOuterWorks(const T& tempParam)
{
typename ob_traits<T>::IntAdapter inner(tempParam);
inner.dump();
}
Without typename here, GCC will assume that IntAdapter is an identifier, and will expect you to be forming an expression rather than a variable declaration.
Also note that you do not have to put semicolons after method bodies!
StructWrapper is inheriting from the primary class template (ie the least specialized), which does not define IntWrapper, so it cannot be used in this class. I'm not sure if instantiating a StructWrapper with one of the more specialized types will allow it to work, or if it fails on compiling the class definition itself.
Compile fails because IntAdapter only appears in the specialized template, and therefore it is not visible at the referring point.
Not clear what would you use it for? Please clarify the circumstances.