Templates and Array of structs that contain pointer to method in class - c++

I am trying to create a class that defines an array of command structs, each of which has two CHAR variables, one CHAR*, one INT and a pointer to a void function that accepts two CHAR arguments. There will be multiple instances of this array, each in a different class. I feel like I am close, but missing something critical. The Arduino GNU compiler seems to agree that I am missing something. Here's the code (with modifications as per Bo R);
<<<<<<<<<< Commands.h >>>>>>>>>>>>>>>>>
#pragma once
//template <class T>
class Commands {
public:
typedef void ( Commands::*FunctionPointer )( char, char );
struct command {
char sel;
char act;
char const *desc;
FunctionPointer funcPtr;
};
command myCommands [2] = {
command { 'a','?',"FOO", &Commands::foo },
command { 'b','x',"BAR", &Commands::bar },
};
int cmdSize = sizeof ( myCommands ) / sizeof ( myCommands [0] );
void foo ( char sel, char act ) {
show ( { sel }, { act } );
}
void bar ( char sel, char act ) {
show ( { sel }, { act } );
}
void show ( char sel, char act ) {
Serial.print ( "SEL = " );
Serial.print ( sel );
Serial.print ( " ACT = " );
Serial.println ( act );
}
void execute ( char sel, char act ) {
for (int i = 0; i < cmdSize; i++) {
if (myCommands [i].sel == sel && myCommands [i].act == act) {
Serial.println ( myCommands [i].desc );
( this->*myCommands [i].funcPtr )( sel, act );
return;
}
}
Serial.print ( F ( "Unknown SEL/ACT Pair:" ) );
Serial.print ( sel );
Serial.print ( '/' );
Serial.println ( act );
}
};
<<<<<<<<<< StructArray.ino >>>>>>>>>>>>>>>>>
#include "Commands.h"
Commands cmd;
void setup() {
Serial.begin ( 115200 );
Serial.println ( "EXECUTING:" );
cmd.execute ( 'a', '?' );
cmd.execute ( 'b', '?' );
cmd.execute ( 'b', 'x' );
Serial.println ( "DONE" );
}
void loop(){}
If I refactor Commands into Template.h and Foo.h (as below), I get four compile errors that I don't understand how to fix:
Severity Code Description File Line
Error error: invalid use of template-name 'Template' without an argument list D:\Documents\Arduino\StructArray\Foo.h 6
Error error: 'myCommands' was not declared in this scope D:\Documents\Arduino\StructArray\Foo.h 11
Error error: 'myCommands' was not declared in this scope D:\Documents\Arduino\StructArray\Foo.h 11
Error error: invalid use of template-name 'Foo' without an argument list D:\Documents\Arduino\StructArray\StructArray.ino 7
Here is the code for Template.h:
#pragma once
template <class T>
class Template {
public:
typedef void ( T::*FunctionPointer )( char, char );
struct command {
char sel;
char act;
char const *desc;
FunctionPointer funcPtr;
};
void show ( char sel, char act ) {
Serial.print ( "SEL = " );
Serial.print ( sel );
Serial.print ( " ACT = " );
Serial.println ( act );
}
void execute ( char sel, char act, int cmdSize ) {
for (int i = 0; i < cmdSize; i++) {
if (T::myCommands[i].sel == sel && T::myCommands [i].act == act) {
Serial.println ( T::myCommands [i].desc );
( this->*T::myCommands [i].funcPtr )( sel, act );
return;
}
}
Serial.print ( F ( "Unknown SEL/ACT Pair:" ) );
Serial.print ( sel );
Serial.print ( '/' );
Serial.println ( act );
}
};
And Foo.h:
#pragma once
#include "Template.h"
template<class T>
class Foo {
public:
Template::command myCommands [2] = {
command { 'a','?',"FOO-A", &Foo::foo },
command { 'b','x',"FOO-B", &Foo::bar },
};
int cmdSize = sizeof ( myCommands ) / sizeof ( myCommands [0] );
void foo ( char sel, char act ) {
show ( { sel }, { act } );
}
void bar ( char sel, char act ) {
show ( { sel }, { act } );
}
};

If I start you out on the non-templated version, you will see that you need to make some changes.
class Commands {
public:
typedef void ( Commands::*FunctionPointer )( char, char );
struct command {
char sel;
char act;
char const *desc;
FunctionPointer funcPtr;
};
command myCommands [2] = {
{ 'a','?',"FOO", &Commands::foo },
{ 'b','x',"BAR", &Commands::bar }
};
int cmdSize = sizeof ( this->myCommands ) / sizeof ( this->myCommands [0] );
void foo ( char sel, char act ) {
char buf[2] = {sel};
Serial.println ( buf );
}
void bar ( char sel, char act ) {
char buf[2] = { sel };
Serial.println ( buf );
}
void execute ( char sel, char act ) {
for (int i = 0; i < cmdSize; i++) {
if (myCommands [i].sel == sel && myCommands [i].act == act) {
Serial.println ( myCommands [i].desc );
(this->*myCommands [i].funcPtr)( sel, act );
}
}
}
};
Once that is solved you can attack the templating (which I didn't see the purpose right now in this example since the foo and bar were part of the template class.)

Related

Strange behavior with char pointer and char pointer returned by fonction in C/C++ with "cout"

I have a strange behavior with a char pointer initialized by the value of a return function and with the cout.
All my code is for an Arduino application, this is why I use char pointer, char array and string.h.
I created a class named FrameManager, with a function getDataFromFrame to extract data from a string (in fact a char array). See above:
`char * FrameManager::getDataFromFrame ( const char frame[], char key[] )
{
char *pValue = nullptr;
int frameLength = strlen ( frame );
int previousStartIndex = 0;
for ( int i=0; i<frameLength; i++ ) {
char c = frame[i];
if ( c == ',' ) {
int buffSize = i-previousStartIndex+1;
char subbuff[buffSize];
memset ( subbuff, 0, buffSize ); //clear buffer
memcpy ( subbuff, &frame[previousStartIndex], i-previousStartIndex );
subbuff[buffSize]='\0';
previousStartIndex = i+1;
int buffLength = strlen ( subbuff );
const char *ptr = strchr ( subbuff, ':' );
if ( ptr ) {
int index = ptr-subbuff;
char buffKey[index+1];
memset ( buffKey, 0, index+1 );
memcpy ( buffKey, &subbuff[0], index );
buffKey[index+1]='\0';
char buffValue[buffLength-index];
memset ( buffValue, 0, buffLength-index );
memcpy ( buffValue, &subbuff[index+1], buffLength-index );
buffValue[buffLength-index]='\0';
if ( strcmp ( key,buffKey ) == 0 ) {
pValue = &buffValue[0];
break;
}
}
} else if ( i+1 == frameLength ) {
int buffSize = i-previousStartIndex+1;
char subbuff[buffSize];
memcpy ( subbuff, &frame[previousStartIndex], frameLength-1 );
subbuff[buffSize]='\0';
int buffLength = strlen ( subbuff );
const char *ptr = strchr ( subbuff, ':' );
if ( ptr ) {
int index = ptr-subbuff;
char buffKey[index+1];
memset ( buffKey, 0, index+1 );
memcpy ( buffKey, &subbuff[0], index );
buffKey[index+1]='\0';
char buffValue[buffLength-index];
memset ( buffValue, 0, buffLength-index );
memcpy ( buffValue, &subbuff[index+1], buffLength-index );
buffValue[buffLength-index]='\0';
if ( strcmp ( key,buffKey ) == 0 ) {
pValue = &buffValue[0];
break;
}
}
}
}
return pValue;
}`
In the main(), I created juste a little code to test the returned value:
int main(int argc, char **argv) {
const char frame[] = "DEVICE:ARM,FUNC:MOVE_F,PARAM:12,SERVO_S:1";
FrameManager frameManager;
char key[] = "DEVICE";
char *value;
value = frameManager.getDataFromFrame(frame, &key[0]);
cout << "Retrieved value: " << value << endl;
cout << "Retrieved value: " << frameManager.getDataFromFrame(frame, &key[0]) << endl;
printf("%s",value);
return 0;
}
and here the result:
Retrieved value: y%R
Retrieved value: ARM
ARM
The first "cout" doesn't display the expected value.
The second "cout" display the expected value and the printf too.
I don't understand what is the problem with the first "cout".
Thanks
Jocelyn
pValue points into local arrays, which get out of scope. That's undefined behavior. It might work, but your program might also crash, return wrong values (that's what you experience), corrupt your data or do any other arbitrary action.
Given that you're already using C++, consider using std::string as a result instead or point into the original frame (if possible).

Http C++ client cannot connect to C++ server through internet

I am trying to create a connection between my local application and my remote application. I used HTTP protocol, when testing in local network, my client-server code had successfully sent file to each other; however, the client couldn't connect to server when i pushed my server code to running on Cloud.
Below is my client-server code in C++. In the code, i tried to send an image from client to server.
client.c
#define EXAMPLE_RX_BUFFER_BYTES (921600)
#define IMAGE_SIZE 921600
static int callback_example( struct lws *wsi, enum lws_callback_reasons reason, void *user, void *in, size_t len )
{
switch( reason )
{
case LWS_CALLBACK_CLIENT_ESTABLISHED:
lws_callback_on_writable( wsi );
break;
case LWS_CALLBACK_CLIENT_RECEIVE:
break;
case LWS_CALLBACK_CLIENT_WRITEABLE:
{
FILE * check_file;
check_file = fopen("test_buff.jpg", "r");
unsigned char buf[LWS_SEND_BUFFER_PRE_PADDING + EXAMPLE_RX_BUFFER_BYTES + LWS_SEND_BUFFER_POST_PADDING];
fread(&buf[LWS_SEND_BUFFER_PRE_PADDING], 1, IMAGE_SIZE, check_file);
printf("%ld\n", sizeof(buf));
printf("hello\n");
printf("%d\n", LWS_SEND_BUFFER_POST_PADDING);
unsigned char *p = &buf[LWS_SEND_BUFFER_PRE_PADDING];
size_t n = IMAGE_SIZE;
lws_write( wsi, p, n, LWS_WRITE_TEXT ); //send
break;
}
case LWS_CALLBACK_CLOSED:
case LWS_CALLBACK_CLIENT_CONNECTION_ERROR:
web_socket = NULL;
break;
default:
break;
}
return 0;
}
enum protocols
{
PROTOCOL_EXAMPLE = 0,
PROTOCOL_COUNT
};
static struct lws_protocols protocols[] =
{
{
"example-protocol",
callback_example,
0,
EXAMPLE_RX_BUFFER_BYTES,
},
{ NULL, NULL, 0, 0 } /* terminator */
};
int main( int argc, char *argv[] )
{
struct lws_context_creation_info info;
memset( &info, 0, sizeof(info) );
info.port = CONTEXT_PORT_NO_LISTEN;
info.protocols = protocols;
info.gid = -1;
info.uid = -1;
struct lws_context *context = lws_create_context( &info );
time_t old = 0;
while( 1 )
{
struct timeval tv;
gettimeofday( &tv, NULL );
if( !web_socket && tv.tv_sec != old )
{
struct lws_client_connect_info ccinfo = {0};
ccinfo.context = context;
ccinfo.address = "https://http-server.wise-paas.io";
ccinfo.port = 8080;
ccinfo.path = "/";
ccinfo.host = lws_canonical_hostname( context );
ccinfo.origin = "origin";
ccinfo.protocol = protocols[PROTOCOL_EXAMPLE].name;
web_socket = lws_client_connect_via_info(&ccinfo);
}
if( tv.tv_sec != old )
{
lws_callback_on_writable( web_socket );
old = tv.tv_sec;
}
lws_service( context, 250 );
sleep(1);
}
lws_context_destroy( context );
return 0;
}
server.c
static int callback_http( struct lws *wsi, enum lws_callback_reasons reason, void *user, void *in, size_t len )
{
switch( reason )
{
case LWS_CALLBACK_HTTP:
lws_serve_http_file( wsi, "example.html", "text/html", NULL, 0 );
break;
default:
break;
}
return 0;
}
int count = 0;
int length = 0;
struct payload
{
unsigned char data[LWS_SEND_BUFFER_PRE_PADDING + IMAGE_SIZE + LWS_SEND_BUFFER_POST_PADDING];
size_t len;
} received_payload;
static int callback_example( struct lws *wsi, enum lws_callback_reasons reason, void *user, void *in, size_t len )
{
switch( reason )
{
case LWS_CALLBACK_RECEIVE:
//while(length < IMAGE_SIZE){
memcpy( &received_payload.data[LWS_SEND_BUFFER_PRE_PADDING + length], in, len );
// for(int i =16; i < (LWS_SEND_BUFFER_PRE_PADDING + len); i++){
// printf("%c\t", received_payload.data[i]);
// }
length+=len;
received_payload.len = length;
// printf("\n\nlength: %d \n", length);
//}
lws_callback_on_writable_all_protocol( lws_get_context( wsi ), lws_get_protocol( wsi ) );
//unsigned char *p = &received_payload.data[LWS_SEND_BUFFER_PRE_PADDING];
// count++;
if(length >= 921600){
length = 0;
}
printf("hello for saving\n");
printf("%d\n%d\n", len, sizeof(received_payload.data));
FILE *receive_test;
receive_test = fopen("write", "w");
fwrite(&received_payload.data[LWS_SEND_BUFFER_PRE_PADDING], 1, IMAGE_SIZE, receive_test);
fclose(receive_test);
break;
case LWS_CALLBACK_SERVER_WRITEABLE:
lws_write( wsi, &received_payload.data[LWS_SEND_BUFFER_PRE_PADDING], received_payload.len, LWS_WRITE_TEXT );
break;
default:
break;
}
return 0;
}
enum protocols
{
PROTOCOL_HTTP = 0,
PROTOCOL_EXAMPLE,
PROTOCOL_COUNT
};
static struct lws_protocols protocols[] =
{
/* The first protocol must always be the HTTP handler */
{
"http-only", /* name */
callback_http, /* callback */
0, /* No per session data. */
0, /* max frame size / rx buffer */
},
{
"example-protocol",
callback_example,
0,
EXAMPLE_RX_BUFFER_BYTES,
},
{ NULL, NULL, 0, 0 } /* terminator */
};
int main( int argc, char *argv[] )
{
struct lws_context_creation_info info;
memset( &info, 0, sizeof(info) );
info.port = 8080;
info.protocols = protocols;
info.gid = -1;
info.uid = -1;
struct lws_context *context = lws_create_context( &info );
while( 1 )
{
lws_service( context, /* timeout_ms = */ 1000000 );
}
lws_context_destroy( context );
return 0;
}

C++: va_list error generic thunk code fails for method

This is my class:
class ControlBoard : public ILCD
{
virtual void print(const GFX_STRING &string, ...);
// ...
This my interface:
class ILCD
{
virtual void print(const GFX_STRING &string, ...) = 0;
// ...
This is my method:
void ControlBoard::print(const GFX_STRING &string, ...)
{
va_list args;
va_start(args, string);
// ...
va_end(args);
}
And this is the compilation error:
error: generic thunk code fails for method 'virtual void ControlBoard::print(const GFX_STRING&, ...)' which uses '...'
If the method "print()" is not in my ILCD interface, the compilation is fine. But I need to add it, so I don't understand why this error appears ?
Thank you very much !
A simple c code with va_list
int WriteLog ( const char *pszBuffer, ... )
{
FILE *fp;
int iRet = FAIL;
va_list vaListArguments = NULL;
fp = _tfopen( LOGPATH, "a" );
if( NULL == fp )
{
return FAIL;
}
if( NULL != pszBuffer )
{
va_start( vaListArguments, pszBuffer );
if( NULL != vaListArguments )
{
iRet = _vftprintf(fp, pszBuffer, vaListArguments);
if( 0 <= iRet )
{
_ftprintf( fp, " \n");
fflush( fp );
iRet = SUCCESS;
}
}
va_end(vaListArguments);
fclose( fp );
}
return iRet;
}

C++ Logger Runtime Threshold

namespace Log {
#include <ctime>
#include <string>
#include <boost\scoped_ptr.hpp>
#ifndef LOG_PREPEND_TIMESTAMP_DEFAULT
#define LOG_PREPEND_TIMESTAMP_DEFAULT false
#endif
enum LogLevel_t { logFatal = 0, logError = 1, logWarning = 2, logVerbose = 3, logDebug = 4 };
std::string LogLevelToString( const LogLevel_t level ) {
static const char* const buffer[] = { "Fatal", "Error", "Warning", "Verbose", "Debug" };
return buffer[level];
}
class Log: public boost::noncopyable {
protected:
boost::scoped_ptr< std::ostringstream > Output_String;
bool m_Prepending_Timestamp;
size_t m_LinesOutputted;
public:
Log():
Output_String( new std::ostringstream ),
m_Prepending_Timestamp( LOG_PREPEND_TIMESTAMP_DEFAULT ),
m_LinesOutputted( 0 ) {}
void UsingTimestamp( bool Prepending_Timestamp = true ) {
m_Prepending_Timestamp = Prepending_Timestamp;
}
std::ostringstream& Get( const LogLevel_t level ) {
// Write line number
++m_LinesOutputted;
*Output_String << m_LinesOutputted << " | ";
if( m_Prepending_Timestamp == true ) {
//prepare a timestamp
time_t now = time( NULL );
std::string formatted_time( asctime( localtime( &now ) ) ); /* &now can be replaced with the above call when r-value references work (maybe) saving a stack var */
formatted_time.erase(( formatted_time.length( ) - 1 ), 1 ); /* Removes the \n(newline) that asctime adds for better formatting */
// Write timestamp to stream
*Output_String << formatted_time << " || ";
}
// Write Logging level(severity) to stream
*Output_String << LogLevelToString( level ) << " || ";
return *Output_String;
}
void Flush() {
*Output_String << std::endl;
fprintf( stdout, "%s", Output_String->str( ).c_str( ) );
fflush( stdout );
Output_String.reset( new std::ostringstream ); /* streams have lots of internal state clean streams are good */
}
~Log() {
*Output_String << std::endl;
fprintf( stdout, "%s", Output_String->str( ).c_str( ) );
fflush( stdout );
}
};
How would I implement a threshold without a macro?
If I wrap the body of get with a check I still have to return the stringstream.
I could change the return type to a pointer instead of a reference then return NULL but then every logger statement would have to have a null check for the returned stringstream

Roman to decimal conversion

What do you think about this code? Is it the best way? Any improvement?
Roman.h
#ifndef ROMAN_H
#define ROMAN_H
#include <string>
#include <map>
typedef unsigned long int UL_I;
typedef std::map< std::string, UL_I, std::less< std::string > > Map;
class Roman_Number
{
public:
//Constructor
Roman_Number( std::string );
void Convert_to_decimal();
UL_I get_Decimal() const;
std::string get_Roman() const;
private:
std::string s_roman_number;
UL_I d_number;
Map pairs;
Map pairs_substracting;
//Utilitaries functions
void _validate_();
void _initilize_pairs_()
{
pairs.insert( Map::value_type( "I", 1 ) );
pairs_substracting.insert( Map::value_type ( "IV", 4 ) );
pairs.insert( Map::value_type( "V", 5 ) );
pairs_substracting.insert( Map::value_type( "IX", 9 ) );
pairs.insert( Map::value_type( "X", 10 ) );
pairs_substracting.insert( Map::value_type( "XL", 40 ) );
pairs.insert( Map::value_type( "L", 50 ) );
pairs_substracting.insert( Map::value_type( "XC", 90 ) );
pairs.insert( Map::value_type( "C", 100 ) );
pairs_substracting.insert( Map::value_type( "CD", 400 ) );
pairs.insert( Map::value_type( "D", 500 ) );
pairs_substracting.insert( Map::value_type( "CM", 900 ) );
}
UL_I _recursive_convert( std::string );
};
#endif
Roman.cpp
#include <iostream>
#include "Roman.h"
void Roman_Number::_validate_()
{
std::cout << "Validating" << std::endl;
}
Roman_Number::Roman_Number(std::string r_number )
{
_initilize_pairs_();
s_roman_number = r_number;
d_number = 0;
}
void Roman_Number::Convert_to_decimal()
{
std::string s_aux = s_roman_number;
d_number = _recursive_convert( s_aux );
}
UL_I Roman_Number::_recursive_convert( std::string new_roman )
{
if( new_roman == "" )
return 0;
if( pairs_substracting.find( new_roman.substr( 0 , 2 ) ) != pairs_substracting.end() )
return pairs_substracting[new_roman.substr( 0, 2 )] +
_recursive_convert( new_roman.erase( 0, 2) );
else
return pairs[new_roman.substr( 0, 1 )] + _recursive_convert( new_roman.erase( 0, 1 ) );
}
UL_I Roman_Number::get_Decimal() const
{
return d_number;
}
std::string Roman_Number::get_Roman() const
{
return s_roman_number;
}
main.cpp
#include <iostream>
#include "Roman.h"
int main() {
Roman_Number R_N( "XIL" );
R_N.Convert_to_decimal();
std::cout << R_N.get_Decimal();
return 0;
}
How about this? http://codepad.org/mJ05BldC
#include <stdio.h>
int main( void ) {
const char* s = "MCDXLIV";
int x = 0; // result
int j,m=0; // max used digit
const char* p=s, *q; while(*p) ++p;
for( --p; p>=s; p-- ) for( q="IVXLCDM",j=0; *q; q++,j++ ) if( *p==*q )
x += ((j>=m)?m=j,1:-1) * (1+j%4/2*9) * (1+j/4*99) * (1+j%2*4);
printf( "s=%s x=%i\n", s, x );
}
Given
public static final String romanNums = "IVXLCDM";
public static void main(String[] args) {
Scanner console = new Scanner(System.in);
String input = console.nextLine();
int arabInt = 0;
for (int i = 0; i < romanNums.length(); i++) {
for (int j = 0; j < input.length(); j++) {
if (input.substring(j, j + 1).equals(romanNums.substring(i, i + 1))) {
arabInt += convertRomToNum(i);
if (j > 0 && romanNums.indexOf(input.substring(j, j + 1)) > romanNums.indexOf(input.substring(j - 1, j))) {
arabInt -= 2 * convertRomToNum(romanNums.indexOf(input.substring(j - 1, j)));
}
}
}
// AFTER OBSERVING PATTERN: 1, 5, 10, 50, 100, 500, 1000; AND ASSOCIATING INDEXES
// OF EACH ROMAN LETTER WITH CORRESPONDING NUMBER IN SEQUENCE ABOVE
public static int convertRomToNum(int i) {
int numBehindLetter = (int) (Math.pow(2, Math.floor(i / 2)) * Math.pow(5, Math.ceil(i / 2.)));
return numBehindLetter;
}
1 = 5^0 * 2^0; 5 = 5^1*2^0; 10 = 5^1*2^0; 50 = 5^2*2^1; 100 = 5^2*2^2; 500 = 5^3*2^2; 1000 = 5^3*2^3 and so on. This is why I have used 'floor' and 'ceil' functions.
Somewhere between convoluted and readable ...
int convRomanToInt(string roman) {
char[] symbol = { 'M', 'D', 'C', 'L', 'X','V','I' };
int[] weight = { 1000, 500, 100, 50, 10, 5 , 1 };
int res = 0, rom = 0, num = 0;
while (rom < roman.Length){
if (roman[rom] == symbol[num]){
res += weight[num];
rom++;
} else if (rom < roman.Length-1 && roman[rom+1] == symbol[num]){
res -= weight[(num&~1)+2];
rom++;
} else {
num++;
}
}
return res;
}