I'm a new C++ user from the Java world. Here is the context: Different class needs to implement foo() function from Base class. But this function has different combination of my_type as input. I'm feeling using something like std::get<2>(input[1]) everywhere in the code is not easy to read and understand. Is there a elegant way to access content in an std::variant? Demo https://shorturl.at/tLQV3
#include <iostream>
#include <variant>
#include <vector>
using my_type = std::variant<int, float, bool>;
struct Base {
virtual void foo(std::vector<my_type>) = 0;
virtual ~Base() {};
};
struct B : Base {
static constexpr int kMetricRawDataTypes[] = {2,2,2,2};
void foo(std::vector<my_type> input) {
bool num_0 = std::get<2>(input[0]); // Question1.1 - is there any more elegant way to access the value?
bool num_1 = std::get<2>(input[1]);
bool num_2 = std::get<2>(input[2]);
bool num_3 = std::get<2>(input[3]);
std::cout << "input " << num_0 << " " << num_1 << " " << num_2 << " " << num_3 << std::endl;
}
};
struct A : Base {
static constexpr int kMetricRawDataTypes[] = {1, 2, 0, 1};
void foo(std::vector<my_type> input) {
float num_0 = std::get<1>(input[0]); // Question 1.2 - is there any more elegant way to access the value?
bool num_1 = std::get<2>(input[1]);
int num_2 = std::get<0>(input[2]);
float num_3 = std::get<1>(input[3]);
std::cout << "input " << num_0 << " " << num_1 << " " << num_2 << " " << num_3 << std::endl;
}
};
int main() {
my_type num1 = 1.0f;
my_type num2 = true;
my_type num3 = 5;
my_type num4 = 3.0f;
std::vector<my_type> input = {num1, num2, num3, num4};
A a;
a.foo(input);
return 0;
}
I feel there should be good solution using template. Please advise!
I'd use the validate function in my old answer as input and rewrite it slightly to fit your new class definition. Then to print the contained types, you could fold over operator,. To only have to implement foo once, you could put that in a CRTP base for A and B. I've chosen to make the validate function a member of the CRTP base here.
#include <iostream>
#include <variant>
#include <vector>
using my_type = std::variant<int, float, bool>;
struct Base {
virtual ~Base() = default;
virtual void foo(const std::vector<my_type>& input) const = 0;
};
template<class T> // A CRTP base for A and B
struct foo_impl : Base {
bool validate(const std::vector<my_type>& input) const {
return input.size() == std::size(T::kMetricRawDataTypes)
&& [&]<std::size_t... Is>(std::index_sequence<Is...>) {
// fold over && :
return (... && (input[Is].index() ==
T::kMetricRawDataTypes[Is]));
}(std::make_index_sequence<std::size(T::kMetricRawDataTypes)>());
}
void foo(const std::vector<my_type>& input) const override {
if(validate(input)) {
std::cout << "input";
[&]<std::size_t... Is>(std::index_sequence<Is...>) {
// fold over , (comma) to print:
((std::cout << ' ' <<
std::get<T::kMetricRawDataTypes[Is]>(input[Is])),
...);
}(std::make_index_sequence<std::size(T::kMetricRawDataTypes)>());
std::cout << '\n';
} else {
std::cout << "not valid\n";
}
}
};
struct A : foo_impl<A> { // inherit with `A` as a template parameter
static constexpr int kMetricRawDataTypes[] = {1, 2, 0, 1};
};
struct B : foo_impl<B> { // inherit with `B` as a template parameter
static constexpr int kMetricRawDataTypes[] = {2, 2, 2, 2};
};
Demo
Related
I have class A which has methods void fun(int, int) and void fun1(int, int). These are non-static methods.
struct A {
void fun(int,int){}
void fun1(int,int){}
};
Now inside class B I want to store pointer to one of the method.
Which means object1 of B will have pointer to fun and object2 of B will have pointer to fun1.
Now my set_handler() and pointer to handler has to be generic.
One way is to use function pointers.
So that that I can use void(A::*pointer)(int,int) which can store address of fun or fun1.
struct B {
typedef void(A::*pointer)(int,int);
pointer f;
void set_handler(pointer p) { f = p; }
};
int main() {
{
B object1;
object2.set_handler(&A::fun);
}
{
B object2;
object2.set_handler(&A::fun1);
}
}
I was looking into boost::bind() but it needs specific name. How do I use boost here?
I malled your question into running code that actually does something with the pointer - so we know when the goal has been achieved:
Live On Coliru
#include <iostream>
struct A {
void fun(int a, int b) { std::cout << __FUNCTION__ << "(" << a << "," << b << ")" << std::endl; }
void fun1(int a, int b) { std::cout << __FUNCTION__ << "(" << a << "," << b << ")" << std::endl; }
};
struct B {
typedef void (A::*pointer)(int, int);
pointer f;
void set_handler(pointer p) { f = p; }
void run(A& instance) {
(instance.*f)(42, 42);
}
};
int main() {
B object1;
B object2;
object1.set_handler(&A::fun);
object2.set_handler(&A::fun1);
A a;
object1.run(a);
object2.run(a);
}
Prints
fun(42,42)
fun1(42,42)
Using boost::function or std::function
You have to allow for the instance argument (the implicit this parameter):
Live On Coliru
struct B {
using function = std::function<void(A&, int, int)>;
function f;
void set_handler(function p) { f = p; }
void run(A& instance) {
f(instance, 42, 42);
}
};
Which prints the same output. Of course you can use boost::function and boost::bind just the same
What about bind?
Bind comes in when you want to adapt the function signatures. So, e.g. you want to bind to any instance of A& without actually passing it into run():
Live On Coliru
#include <iostream>
#include <functional>
struct A {
std::string name;
void fun(int a, int b) { std::cout << "name:" << name << " " << __FUNCTION__ << "(" << a << "," << b << ")" << std::endl; }
void fun1(int a, int b) { std::cout << "name:" << name << " " << __FUNCTION__ << "(" << a << "," << b << ")" << std::endl; }
};
struct B {
using function = std::function<void(int, int)>;
function f;
void set_handler(function p) { f = p; }
void run() {
f(42, 42);
}
};
int main() {
B object1;
B object2;
A a1 {"black"};
A a2 {"white"};
{
using namespace std::placeholders;
object1.set_handler(std::bind(&A::fun, &a1, _1, _2));
object2.set_handler(std::bind(&A::fun1, &a2, _1, _2));
}
object1.run();
object2.run();
}
Which prints:
name:black fun(42,42)
name:white fun1(42,42)
More Goodness
From c++ you can do without bind and its pesky placeholders (there are other caveats, like bind storing all arguments by value). Instead, you may use lambdas:
Live On Coliru
#include <iostream>
#include <functional>
struct A {
std::string name;
void fun(int a, int b) { std::cout << "name:" << name << " " << __FUNCTION__ << "(" << a << "," << b << ")" << std::endl; }
void fun1(int a, int b) { std::cout << "name:" << name << " " << __FUNCTION__ << "(" << a << "," << b << ")" << std::endl; }
};
struct B {
using function = std::function<void(int, int)>;
function f;
void set_handler(function p) { f = p; }
void run() {
f(42, 42);
}
};
int main() {
B object1;
B object2;
object1.set_handler([](int a, int b) {
A local_instance {"local"};
local_instance.fun(a*2, b*3); // can even do extra logic here
});
A main_instance {"main"};
object2.set_handler([&main_instance](int a, int b) {
main_instance.fun1(a, b); // can even do extra logic here
});
object1.run();
object2.run();
}
Prints
name:local fun(84,126)
name:main fun1(42,42)
I am trying to understand template specialization in C++. I have read other forums, but cannot get it working in practice. I am trying to learn with a very simple example which I will explain.
What I would like to accomplish: I want foo to exhibit different behaviors based on the type. The code below does not work, but I have commented the behavior I would like to see. Could someone please fill in the lines that I commented. Please let me know if anything is unclear.
#include <iostream>
#include <string>
template <typename T>
class my_template
{
public:
foo() {return 0} // default behavior if there does not exist foo() function for the specified type
};
template <>
class my_template<int>
{
public:
// implement foo function: should return -1 if the type = int
};
template <>
class my_template<long>
{
public:
// implement foo function: should return 100 if the type = long
};
int main()
{
my_template<int> x;
my_template<long> y;
my_template<double> z;
std::cout << x.foo() << "\n"; // print -1
std::cout << y.foo() << "\n"; // print 100
std::cout << z.foo() << "\n"; // print 0
return 0;
}
Just to show you a few different approaches.
If you use a metafunction approach, then nothing will ever be done at run-time (guaranteed):
template<typename>
struct my_template{
enum { value = 0 };
};
template<>
struct my_template<int>{
enum { value = -1 };
};
template<>
struct my_template<long>{
enum { value = 100 };
};
int main(){
std::cout << "float: " << my_template<float>::value << '\n';
std::cout << "int: " << my_template<int>::value << '\n';
std::cout << "long: " << my_template<long>::value << '\n';
}
Or you could use a template variable ( C++14 ):
template<typename>
constexpr int my_value = 0;
template<>
constexpr int my_value<int> = -1;
template<>
constexpr int my_value<long> = 100;
int main(){
std::cout << "float: " << my_value<float> << '\n';
std::cout << "int: " << my_value<int> << '\n';
std::cout << "long: " << my_value<long> << '\n';
}
Or use a template function:
template<typename T>
int func_impl(T){ return 0; }
int func_impl(int){ return -1; }
int func_impl(long){ return 100; }
template<typename T>
int func(){
return func_impl(T(0));
}
int main(){
std::cout << "float: " << func<float>() << '\n';
std::cout << "int: " << func<int>() << '\n';
std::cout << "long: " << func<long>() << '\n';
}
template <typename T>
class my_template
{
public:
int foo() {return 0;} // default behavior
};
template <>
class my_template<int>
{
public:
int foo() {return -1;}
};
Is that enough?
I've a class withmap<string,vector<string>>.
I want to give a user a member function to receive the value for a key in different formats than std::vector(string):
vector(string),
string,
vector(int),
vector(float) and
bool
example:
bool x = (bool) myClass["dummy_boolean_type"]
x = myClass["dummy_boolean_type"].as<bool>
int y = (int) myClass["dummy_boolean_type"]
Can someone have an example what is the best way to achieve it ?
(without a use in Boost)
You cannot provide your class with any member function or functions
that will support the two constructions you want:
T x = myClassInstance["key"].as<T> // (1)
T x = (T) myClassInstance["key"] // (2)
In the case of (1), the immediate reason is simply that the construction is
not legal C++. So let's suppose it is replaced by:
T x = myClassInstance["key"].as<T>() // (1a)
But this doesn't help, and the reason is the same for both (1a) and (2):
The expression myClassInstance["key"] will have to evaluate to some object e or reference to such that is returned by:
myClass::operator[](std::string const &);
This e is the vector<string> to which key maps in your
map<string,vector<string> data member of myClass. It is not myClassInstance.
So what you are asking for are member functions of myClass that will support
the constructions:
T x = e.as<T> // (1b)
T x = (T) e // (2b)
where e is an std::vector<std::string>.
Clearly, nothing you can do in myClass can address your requirement. In
(1b) and (2b), myClass is nowhere to be seen.
Is there any template member function of std::vector<std::string>:
template<typename T>
T as() const;
that has the behaviour you want for (1b)?
Does std::vector<std::string> have any template member function:
template<typename T>
operator T() const;
that has the behaviour you want for (2b)?
No and No.
However...
You can implement an as template member function of myClass that
supports conversions such as you mention. Its signature - of course -
would be:
template<typename T>
T myClass::as(std::string const & key) const;
and you would invoke it like:
T x = myClassInstance.as<T>("key") // (1c)
I'll sketch an implemention that assumes we're content with the
conversions from std::vector<std::string> to:
std::string
std::vector<int>
bool
which will be enough to get you under way.
To convert an std::vector<std::string> vs to std::string I'll concatenate
the elements of vs.
To convert an std::vector<std::string> vs to std::vector<int> I'll convert each element of vs from a decimal numeral, if I can, to the
integer the numeral represents, and return a vector of those integers. Without
prejudice to other policies I'll throw an std::invalid_argument exception
when an element doesn't trim to a decimal numeral.
I am spoilt for choice as to what you might mean by converting an std::vector<std::string>
to bool, so I will arbitrarily say that vs is true if I can convert it
to a vector<int> of which any element is non-0 and is false if I can convert
it to a vector<int> in which all elements are 0.
The sketch:
#include <type_traits>
#include <map>
#include <vector>
#include <string>
#include <algorithm>
namespace detail {
template<typename T>
struct convert_to
{
static T from(std::vector<std::string> const & vs) {
static constexpr bool always_false = !std::is_same<T,T>::value;
static_assert(always_false,
"Calling `convert_to<T>::from` for unimplemented `T`");
return *(T*)nullptr;
}
};
template<>
std::string convert_to<std::string>::from(std::vector<std::string> const & vs)
{
std::string s;
for ( auto const & e : vs ) {
s += e;
}
return s;
}
template<>
std::vector<int>
convert_to<std::vector<int>>::from(std::vector<std::string> const & vs)
{
auto lamb = [](std::string const & s) {
std::size_t lastoff = s.find_last_not_of(" \t\f\v\n\r");
int i;
try {
std::size_t nlen;
i = std::stoi(s,&nlen);
if (nlen <= lastoff) {
throw std::invalid_argument("");
}
}
catch(std::invalid_argument const & e) {
throw std::invalid_argument(
"Cannot convert \"" + s + "\" to int");
}
return i;
};
std::vector<int> vi;
std::transform(vs.begin(),vs.end(),std::back_inserter(vi),lamb);
return vi;
}
template<>
bool convert_to<bool>::from(std::vector<std::string> const & vs)
{
auto vi = convert_to<std::vector<int>>::from(vs);
for (auto const & i : vi) {
if (i) {
return true;
}
}
return false;
}
} // namespace detail
struct myClass // Your class
{
// Whatever...
std::vector<std::string> & operator[](std::string const & key) {
return _map[key];
}
template<typename T>
T as(std::string const & key) {
return detail::convert_to<T>::from(_map[key]);
}
// Whatever...
private:
std::map<std::string,std::vector<std::string>> _map;
};
The one take-away point here is the use of template<typename T>
detail::struct convert_to, with its solitary static member function:
T from(std::vector<std::string> const & vs)
which in the default instantiation will provoke a static_assert failure
reporting that no conversion to T from std::vector<std::string> has been
defined.
Then, for each type U to which you want a conversion, you have just to
write a specializing definition:
template<>
U convert_to<U>::from(std::vector<std::string> const & vs);
as you see fit, and the construction (1c) will use it as per:
template<typename T>
T myClass::as(std::string const & key) {
return detail::convert_to<T>::from(_map[key]);
}
Here's an illustrative progam you can append to the sketch:
#include <iostream>
using namespace std;
template<typename T>
static void print_vec(std::vector<T> const & v)
{
cout << "{ ";
for (auto const & e : v) {
cout << e << " ";
}
cout << "}\n";
}
static void print_vec(std::vector<std::string> const & v)
{
cout << "{ ";
for (auto const & e : v) {
cout << '\"' << e << "\" ";
}
cout << "}\n";
}
int main()
{
myClass f;
f["int_vec"] = vector<string>{"0","1 "," 2"};
cout << "f[\"int_vec\"] = "; print_vec(f["int_vec"]);
f["true_vec"] = vector<string>{"0"," 1 ","0"};
cout << "f[\"true_vec\"] = "; print_vec(f["true_vec"]);
f["false_vec"] = vector<string>{"0"," 0","0 "};
cout << "f[\"false_vec\"] = "; print_vec(f["false_vec"]);
f["not_int_vec0"] = vector<string>{"0","1","2",""};
cout << "f[\"not_int_vec0\"] = "; print_vec(f["not_int_vec0"]);
f["not_int_vec1"] = vector<string>{"0","#","2",};
cout << "f[\"not_int_vec1\"] = "; print_vec(f["not_int_vec1"]);
f["not_int_vec2"] = vector<string>{"0"," 1$","2",};
cout << "f[\"not_int_vec2\"] = "; print_vec(f["not_int_vec2"]);
cout << "f.as<string>(\"int_vec\") = \""
<< f.as<string>("int_vec") << '\"' << endl;
cout << "f.as<string>(\"true_vec\") = \""
<< f.as<string>("true_vec") << '\"' << endl;
cout << "f.as<string>(\"false_vec\") = \""
<< f.as<string>("false_vec") << '\"' << endl;
cout << "f.as<string>(\"not_int_vec0\") = \""
<< f.as<string>("not_int_vec0") << '\"' << endl;
cout << "f.as<string>(\"not_int_vec1\") = \""
<< f.as<string>("not_int_vec1") << '\"' << endl;
cout << "f.as<string>(\"not_int_vec2\") = \""
<< f.as<string>("not_int_vec2") << '\"' << endl;
vector<int> va = f.as<vector<int>>("int_vec");
cout << "f.as<vector<int>>(\"int_vec\") = ";
print_vec(f.as<vector<int>>("int_vec"));
cout << boolalpha << "f.as<bool>(\"true_vec\") = "
<< f.as<bool>("true_vec") << endl;
cout << boolalpha << "f.as<bool>(\"false_vec\") = "
<< f.as<bool>("false_vec") << endl;
try {
cout << "f.as<vector<int>>(\"not_int_vec0\")...";
auto b = f.as<vector<int>>("not_int_vec0");
(void)b;
}
catch(std::invalid_argument const & e) {
cout << e.what() << endl;
}
try {
cout << "f.as<vector<int>>(\"not_int_vec1\")...";
auto b = f.as<vector<int>>("not_int_vec1");
(void)b;
}
catch(std::invalid_argument const & e) {
cout << e.what() << endl;
}
try {
cout << "f.as<vector<int>>(\"not_int_vec2\")...";
auto b = f.as<vector<int>>("not_int_vec2");
(void)b;
}
catch(std::invalid_argument const & e) {
cout << e.what() << endl;
}
// char ch = f.as<char>("int_vec"); <- static_assert fails
return 0;
}
It outputs:
f["int_vec"] = { "0" "1 " " 2" }
f["true_vec"] = { "0" " 1 " "0" }
f["false_vec"] = { "0" " 0" "0 " }
f["not_int_vec0"] = { "0" "1" "2" "" }
f["not_int_vec1"] = { "0" "#" "2" }
f["not_int_vec2"] = { "0" " 1$" "2" }
f.as<string>("int_vec") = "01 2"
f.as<string>("true_vec") = "0 1 0"
f.as<string>("false_vec") = "0 00 "
f.as<string>("not_int_vec0") = "012"
f.as<string>("not_int_vec1") = "0#2"
f.as<string>("not_int_vec2") = "0 1$2"
f.as<vector<int>>("int_vec") = { 0 1 2 }
f.as<bool>("true_vec") = true
f.as<bool>("false_vec") = false
f.as<vector<int>>("not_int_vec0")...Cannot convert "" to int
f.as<vector<int>>("not_int_vec1")...Cannot convert "#" to int
f.as<vector<int>>("not_int_vec2")...Cannot convert " 1$" to int
(gcc 5.1, clang 3.6, C++11)
I am trying to write a map of heterogeneous function pointers and have mimicked that in a smaller program which has functions to either take a "int" or a "double" val.
#include <iostream>
#include <boost/any.hpp>
#include <map>
#include <sstream>
using namespace std;
class Functions
{
public:
void intF(int f) { cout << " Value int : " << f << endl; }
void doubleF(double f) { cout << " Value double : " << f << endl; }
};
const boost::any convertInt(const string& s)
{
cout << " string passed : " << s << endl;
std::istringstream x(s);
int i;
x >> i;
cout << " Int val : " << i << endl;
return i;
}
const boost::any convertDouble(const string& s)
{
cout << " string passed : " << s << endl;
std::istringstream x(s);
double i;
x >> i;
cout << " Double val : " << i << endl;
return i;
}
typedef void (Functions::*callFunc)( const boost::any);
typedef const boost::any (*convertFunc)( const string&);
struct FuncSpec
{
convertFunc _conv;
callFunc _call;
};
FuncSpec funcSpec[] = {
{ &convertInt, (callFunc)&Functions::intF },
{ &convertDouble, (callFunc)&Functions::doubleF },
};
int main()
{
string s1("1");
string s2("1.12");
callFunc c = funcSpec[0]._call;
convertFunc co = funcSpec[0]._conv;
Functions F;
(F.*c)(((*co)(s1)));
c = funcSpec[1]._call;
co = funcSpec[1]._conv;
(F.*c)(((*co)(s2)));
return 0;
}
When I run this program, I see the double value getting printed correctly but the int value is garbled. Could someone help me with this? Also is there a better way to achieve this functionality. In my program I have 2 functions - one taking a vector<int> and the other taking a vector<double>. I have to read the data from a file and call the appropriate setters in the object of the class which has these 2 functions.
Casting a member function to a different type like you are doing isn't valid. Try this instead:
class Functions
{
public:
void intF(boost::any input)
{
int f = boost::any_cast<int>(input);
cout << " Value int : " << f << endl;
}
void doubleF(boost::any input)
{
double f = boost::any_cast<double>(input);
cout << " Value double : " << f << endl;
}
};
.
.
.
FuncSpec funcSpec[] = {
{ &convertInt, &Functions::intF },
{ &convertDouble, &Functions::doubleF },
};
My intention is to refrain from macros style when I need to define a lot of similar methods. So I'm interested, can I use templates or anything like that?
This is the general idea in pseudo-c++:
template <class T, class U> void myMethod(T t, U u){ ..do a lot .. }
class A {
public:
A(){}
void myMethod<int, int>;
void myMethod<float, char>;
// ... etc
};
template <class T, class U> class A
{
public:
void MemberSet( T t, U u );
};
ADDED:
#include <typeinfo>
#include <iostream>
using namespace std;
class A
{
public:
template <class T, class U> void MemberSet( T t, U u ) {
cout << typeid(t).name() << " " << typeid(u).name() << endl;
};
};
int main()
{
A a;
a.MemberSet(5,5);
a.MemberSet<char, long>(5,5);
}
you may want to explicitly instantiate
template void A::MemberSet<int, long> (int, long);
No, but you can use inheritance.
template <class derived_T, class T, class U>
struct base {
void myMethod_(T t, U u) {
// use this to access derived class members:
static_cast<derived_T*>(this)->
}
};
struct a : base<a, int, int>, base<a, float, float> {
template <class T, class U>
void myMethod(T&& t, U&& u) {
base<a,T,U>::myMethod_(std::forward<T>(t), std::forward<U>(u));
}
};
No, but you can:
template <class T, class U> void struct myMethodWrapper
{
void myMethod(T t, U u){ ..do a lot .. }
};
And then:
class A : public myMethodWrapper<int, int>,
public myMethodWrapper<float, float>
{
};
That behaves similarly.
Another option is to put the template code outside the class and call it from class methods.
#include <iostream>
using namespace std;
namespace myTemplates
{
// template method 'mult(a,b)'
// returns a*b
template <class T1, class T2>
T1 mult(T1 a, T2 b)
{
T1 result = a * b;
return result;
}
// template specialization 'mult(string aString, int m)'
// returns a string repeated m times
template <>
string mult<string, int>(string input, int m)
{
string result;
for (int i = 0; i < m; i++)
{
result += input;
}
return result;
}
}
class A {
public:
A(){}
int mult(int a , int b ) { return myTemplates::mult(a, b ) ; }
float mult(float a , float b ) { return myTemplates::mult(a, b ) ; }
string mult(string a , int b ) { return myTemplates::mult(a, b ) ; }
};
int main(void)
{
int iA = 2;
int iB = 3;
int iC = 0; // result
float fA = 20.1;
float fB = 30.3;
float fC = 0.0; // result
string sA = " -blah- ";
string sC; // result
iC = myTemplates::mult(iA,iB);
cout << "mult(" << iA << ", " << iB << ") = " << iC << endl;
fC = myTemplates::mult(fA,fB);
cout << "mult(" << fA << ", " << fB << ") = " << fC << endl;
sC = myTemplates::mult(sA,iB);
cout << "mult(" << sA << ", " << iB << ") = " << sC << endl;
A a;
iC = a.mult(iA,iB);
cout << "a.mult(" << iA << ", " << iB << ") = " << iC << endl;
fC = a.mult(fA,fB);
cout << "a.mult(" << fA << ", " << fB << ") = " << fC << endl;
sC = a.mult(sA,iB);
cout << "a.mult(" << sA << ", " << iB << ") = " << sC << endl;
return 1;
}
output:
mult(2, 3) = 6
mult(20.1, 30.3) = 609.03
mult( -blah- , 3) = -blah- -blah- -blah-
a.mult(2, 3) = 6
a.mult(20.1, 30.3) = 609.03
a.mult( -blah- , 3) = -blah- -blah- -blah-