C++ is possible to make only one method templated? - c++

I have a class and I need only one template method, like this:
/* A.h */
class A {
public:
void foo() const;
private:
template <class T>
void foo2(const T& t, const std::string& s) {
/* */
}
}
This compiles fine, but if in the foo specialization I try to call foo2 I get errors:
/* A.cpp */
void A::foo() {
this->foo2(1, "test");
}
The error is:
passing ‘const A’ as ‘this’ argument of ‘void A::foo2(const T&, const
string&) [with T = int, std::string = std::basic_string<char>]’
discards qualifiers [-fpermissive]

Yes, it is possible.
I think you missed const modifier for void foo() in your example, didn't you?
If my assumption is correct, put a const modifier for foo2 too.

You are calling on the same object a non-const function foo2 from const function foo. Hence the error. BTW this in the call is not necessary:
this->foo2(1, "test");
the following will do too:
foo2(1, "test");

You're missing a ; at the end of your class declaration and your const correctness seems to be inconsistent. This compiles for me in vc12:
/* A.h */
class A {
public:
void foo() const;
private:
template <class T>
void foo2(const T& t, const std::string& s) const {
/* */
}
};
void A::foo() const {
this->foo2(1, "test");
}

Related

How to static_cast a pointer to const member function?

Surprisingly (embarrassingly?) I cannot get the syntax of the static_const of a const member function right. In short (details below) if the member function is not marked const I use:
static_cast<std::vector<double> (mymodule::Foo::*)(const std::vector<double>&)>(&mymodule::Foo::bar)
but marking the member function Foo::bar(...) const the compiler does not know what to do:
error: address of overloaded function 'bar' cannot be static_cast to type 'std::vector<double> (mymodule::Foo::*)(const std::vector<double> &)'
Where should I put the function's constness?
Details
I'm trying to create Python binding for the following module:
namespace mymodule {
class Foo
{
public:
Foo() = default;
template <class T>
T bar(const T& a) const
{
T ret = a;
for (auto& i : ret) {
i *= 2.0;
}
return ret;
}
template <class T>
T bar(const T& a, double f) const
{
T ret = a;
for (auto& i : ret) {
i *= f;
}
return ret;
}
};
} // namespace mymodule
whereby I write the Python bindings with pybind11:
#include <pybind11/pybind11.h>
namespace py = pybind11;
PYBIND11_MODULE(example, m)
{
py::class_<mymodule::Foo>(m, "Foo")
.def(py::init<>())
.def("bar",
static_cast<std::vector<double> (mymodule::Foo::*)(const std::vector<double>&)>(&mymodule::Foo::bar),
py::arg("a"))
.def("bar",
static_cast<std::vector<double> (mymodule::Foo::*)(const std::vector<double>&, double)>(&mymodule::Foo::bar),
py::arg("a"),
py::arg("f"));
}
which fails to compile:
.../example.cpp:54:14: error: address of overloaded function 'bar' cannot be static_cast to type 'std::vector<double> (mymodule::Foo::*)(const std::vector<double> &)'
static_cast<std::vector<double> (mymodule::Foo::*)(const std::vector<double>&)>(&mymodule::Foo::bar),
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
.../example.cpp:19:7: note: candidate function template
T bar(const T& a) const
^
.../example.cpp:29:7: note: candidate function template
T bar(const T& a, double f) const
^
.../example.cpp:58:14: error: address of overloaded function 'bar' cannot be static_cast to type 'std::vector<double> (mymodule::Foo::*)(const std::vector<double> &, double)'
static_cast<std::vector<double> (mymodule::Foo::*)(const std::vector<double>&, double)>(&mymodule::Foo::bar),
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
.../example.cpp:19:7: note: candidate function template
T bar(const T& a) const
^
.../example.cpp:29:7: note: candidate function template
T bar(const T& a, double f) const
^
2 errors generated.
You should add const at last as:
static_cast<std::vector<double> (mymodule::Foo::*)(const std::vector<double>&) const>(&mymodule::Foo::bar),
// ^^^^^

template specialization based on const-qualified instantiation

Suppose I have a templated class:
template<typename T>
class A
{
public:
A(T& val) : m_val{val} {}
T& val() { return m_val; }
const T& val() const { return m_val; }
//etc...
private:
T& m_val;
};
Can I have template specialization which is different for lines (1) and (2):
int a = 5;
A<int> x {a}; //(1)
const A<int> y {a}; //(2)
const int b = 10;
const A<int> z {b}; //error: binding reference of type ‘int&’ to ‘const int’ discards qualifiers
Basically, in the const case I want to declare the underlying m_val as const T& m_val; because I've instantiated my wrapper class as const and I want to signify that the internal reference should also be const in this case.
Is this possible? I've tried several solutions and the only one that seem to work is to explicitly add const to the template argument like this: const A<const int> z {b};
Is it possible to avoid this inner const-qualifier?
EDIT: Changed the member variable to be a reference to show how const-ness can cause trouble for the compiler in this situation.
EDIT2: Removed the default constructor to simplify the problem.

How to resolve an apply_visitor within another static_visitor in boost::variant? [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 5 years ago.
Improve this question
I get a compiler regarding apply_visitor within the current operator.
I tested all the apply_visitor outside of that method and it works perfectly fine. Just when trying to use it within that method it runs into a bunch of issues.
The error message is confusing me.
So, Why is trying to use apply_visitor for a different visitor is running into problems within the current visitor?
Here the Snippet of the code that have give me the errors:
typedef boost::make_recursive_variant<string, int, vector<boost::recursive_variant_ > >::type ObjectE;
class ReturnType : public boost::static_visitor<string> {
public:
string operator()(string &s) { return "string"; }
string operator()(int i) {return "int";}
string operator()(std::vector<ObjectE> const &v) {return "vector";}
};
class ReturnVal : public boost::static_visitor<string> {
public:
string operator()(string &s) { return s; }
string operator()(int i) {return to_string(i);}
string operator()(std::vector<ObjectE> const &v) {return "vector";}
};
class ReturnV : public boost::static_visitor<vector<ObjectE>> {
public:
vector<ObjectE> operator()(string &s){ return {};}
vector<ObjectE> operator()(int i) {return {};}
vector<ObjectE> operator()(vector<ObjectE> const &v) {return v;}
};
struct create_Str {
using result_type = void;
std::ostream & out;
template <typename T> void call(T const &v) { return operator()(v);}
template <typename... Ts> void operator()(boost::variant<Ts...> const &v) {
return boost::apply_visitor(*this, v);
}
void operator()(int i) { out << i; }
void operator()(std::string const &s) { out << s; }
template <typename... Ts> void operator()(std::vector<Ts...> const &v) {
string name = boost::apply_visitor(ReturnVal(), v[0]);
if (v.size() == 3 && isOp(name)) {
}
else if (v.size() == 3 && isListCons(name)) {
call(v[1]);
ObjectE tail = v[2];
for (;;) {
if ("[]" == boost::get<string>(tail) || "nil" == boost::get<string>(tail)) {
break;
}
if ( !(boost::apply_visitor(ReturnType(), tail) == "vector")) {
}
vector<ObjectE> list = boost::apply_visitor(ReturnV(), v[2]);;
if (!(list.size() == 3 && isListCons(boost::apply_visitor(ReturnVal(), list[0])))) {
}
}
}
}
};
At first, I thought maybe
vector<ObjectE> list = v[2];
was the issue. So I created a visitor who will return a vector.
However, it seem that most of the errors are :
error: no match for call to '(const ReturnVal) (std::__cxx11::basic_string<char>&)'
which I'm not sure what it mean.
Can someone explain to me what the issue is?
Hah. Look back at my older answer to you:
Calls like
boost::apply_visitor(ReturnType(), tail)
call pass the visitor as a temporary, so it can only bind to a const&. This means that all call-operator overloads required must be const-qualified, because otherwise they won't apply, as you're being told:
Live On Coliru
#include <boost/variant.hpp>
struct Ok : boost::static_visitor<> {
void operator()(std::string const&) const {}
void operator()(int) const {}
};
struct NotWorkingWithTemporaries : boost::static_visitor<> {
void operator()(std::string const&) const {}
void operator()(int) {} // whoops, missing const-qualifier
};
int main() {
boost::variant<std::string, int> v;
boost::apply_visitor(Ok{}, v);
//boost::apply_visitor(NotWorkingWithTemporaries{}, v); // COMPILE ERROR
// however, this works:
NotWorkingWithTemporaries not_a_temporary;
boost::apply_visitor(not_a_temporary, v);
}
Compiles. Ucommenting the line commented with // COMPILE RROR gives:
Live On Coliru
In file included from /usr/local/include/boost/variant.hpp:17:0,
from main.cpp:1:
/usr/local/include/boost/variant/variant.hpp: In instantiation of 'boo...
/usr/local/include/boost/variant/detail/visitation_impl.hpp:114:9: r...
/usr/local/include/boost/variant/detail/visitation_impl.hpp:154:41: ...
/usr/local/include/boost/variant/detail/visitation_impl.hpp:238:5: r...
/usr/local/include/boost/variant/variant.hpp:2390:48: required from ...
/usr/local/include/boost/variant/variant.hpp:2404:43: required from ...
/usr/local/include/boost/variant/variant.hpp:2429:52: required from ...
/usr/local/include/boost/variant/detail/apply_visitor_unary.hpp:84:43:...
main.cpp:17:56: required from here
/usr/local/include/boost/variant/variant.hpp:1046:24: error: no match ...
return visitor_(operand);
~~~~~~~~^~~~~~~~~
main.cpp:9:10: note: candidate: void NotWorkingWithTemporaries::operat...
void operator()(std::string const&) const {}
^~~~~~~~
main.cpp:9:10: note: no known conversion for argument 1 from 'int' t...
main.cpp:10:10: note: candidate: void NotWorkingWithTemporaries::opera...
void operator()(int) {} // whoops, missing const-qualifier
^~~~~~~~
main.cpp:10:10: note: passing 'const NotWorkingWithTemporaries*' as ...
In file included from /usr/local/include/boost/variant.hpp:17:0,
from main.cpp:1:
/usr/local/include/boost/variant/variant.hpp:1046:32: error: return-st...
return visitor_(operand);
Skip the required from chain, scan for error: first and then notice the note: that says:
main.cpp:10:10: note: candidate: void NotWorkingWithTemporaries::operator()(int) <near match>
void operator()(int) {} // whoops, missing const-qualifier
^~~~~~~~
main.cpp:10:10: note: passing 'const NotWorkingWithTemporaries*' as 'this' argument discards qualifiers
It's pretty clear once you look for it: passing 'const NotWorkingWithTemporaries*' as 'this' argument discards qualifiers. The only thing you need to know is const is known as a qualifier¹.
¹ const, volatile and rvalue-ref (&&)
OTHER REMARKS
Trying to get the rest of your non-self-contained question code to compile reveals similar issues with the std::string overloads:
std::string operator()(std::string const & /*s*/) const { return "std::string"; }
(note std::string const& instead of std::string&).
Other than that... it look as though you're abusing vectors to represent Expressions. Why not make it strong typed and a lot less error-prone?
See e.g. Building a Custom Expression Tree in Spirit:Qi (Without Utree or Boost::Variant)

passing const this to function accepting const pointer is not const-correct?

I have a class template Foo with the following member function:
bool contains(const T& item) const
I have instantiated this with a pointer type: Foo<Bar*>, leading me to expect that the member function will now have the following signature:
bool contains(const Bar*& item) const
In a const Bar member function, I attempt to pass this to Foo<Bar*>::contains:
bool Bar::func(const Foo<Bar*>& foo) const
{
return foo.contains(this);
}
This fails to compile, with the following error:
error: invalid conversion from ‘const Bar*’ to ‘Bar*’
Question:
Why is my const T& parameter not const-correct?
What signature for Foo<T>::contains(...) const is required to allow calling with this to compile?
Full example:
#include <vector>
#include <algorithm>
template<typename T>
struct Foo
{
bool contains(const T& item) const
{
return false;
}
};
struct Bar
{
bool func(const Foo<Bar*>& foo) const
{
return foo.contains(this);
}
};
Error output:
scratch/main.cpp:17:33: error: invalid conversion from ‘const Bar*’ to ‘Bar*’ [-fpermissive]
return foo.contains(this);
^
scratch/main.cpp:7:10: note: initializing argument 1 of ‘bool Foo<T>::contains(const T&) const [with T = Bar*]’
bool contains(const T& item) const
I have instantiated this with a pointer type: Foo<Bar*>, leading me
to expect that the member function will now have the following
signature:
bool contains(const Bar*& item) const
That's where the problem is. When T = Bar*, the expression
bool contains(const T& item) const
Will actually compile to
bool contains(Bar * const & item) const
That is, a reference-to-a-const-pointer-to-Bar.
It makes sense of you think about it: you want T to be const, and then you want a reference to that.
If you want to apply the const in the usual "intended" way (though this might cause some surprises for seasoned C++ programmers), you can declare your container and member function in the following way:
template <class T>
class Container {
public:
using const_bare_type = typename std::conditional<
std::is_pointer<T>::value,
typename std::remove_pointer<T>::type const*,
const T>::type;
bool contains(const const_bare_type& item);
};
Compiler alerts about wrong line, you must write:
bool func(const Foo<const Bar*>& foo) const
I.e. const Bar* in template parameter, because Bar::func receives const Bar * this as its parameter, and cannot convert it to Bar* in template parameter (cannot remove const).

c++ : Universal getter for class

I kind of need help! I want to define a template method for my class to access its private fields. Here is my code:
#include <string>
#include <vector>
using namespace std;
class ex
{
public:
ex(string pegah_,int amin_):pegah(pegah_),amin(amin_){}
template<typename T>
T get_field(){
if(is_same<T,string>::value)
return pegah;
else if(is_same<T,int> ::value)
return amin;
}
private:
string pegah;
int amin;
};
int main(void)
{
string i = "salam";
int o=10;
ex y(i,o);
y.get_field<string>();
}
as you see I want to use just one function. But I keep getting this error:
test.cpp: In instantiation of ‘T ex::get_field() [with T = std::basic_string<char>]’:
test.cpp:30:21: required from here
test.cpp:15:8: error: invalid conversion from ‘int’ to ‘const char*’ [-fpermissive]
return amin;
^
In file included from /usr/include/c++/4.8/string:52:0,
from test.cpp:1:
/usr/include/c++/4.8/bits/basic_string.h:490:7: error: initializing argument 1 of ‘std::basic_string<_CharT, _Traits, _Alloc>::basic_string(const _CharT*, const _Alloc&) [with _CharT = char; _Traits = std::char_traits<char>; _Alloc = std::allocator<char>]’ [-fpermissive]
basic_string(const _CharT* __s, const _Alloc& __a = _Alloc());
can anyone help?
Instead you could lay your code out like this:
template<typename T> T get_field();
// outside the class:
template<> inline int ex::get_field<int>() { return amin; }
template<> inline string ex::get_field<string>() { return pegah; }
As you have it now, all branches of the if..else must compile.
Basically you have three options to do it.
First using explicit specialization of template member function.
class Foo {
public:
template <typename T>
T get () const;
private:
std::string str {"XXX"};
int value {42};
};
template <>
inline std::string Foo::get () const {
return str;
}
template <>
inline int Foo::get () const {
return value;
}
Second one is to use helper function with different parameters type.
class Foo2 {
public:
template <typename T>
T get () const {
return get_helper (typename std::is_same<T, std::string>::type {});
}
private:
std::string get_helper (std::true_type) const {
return str;
}
int get_helper (std::false_type) const {
return value;
}
private:
std::string str {"YYY"};
int value {44};
};
Third option is to use SFINAE.
class Foo3 {
public:
template <typename T>
typename std::enable_if<std::is_same<T, std::string>::value, T>::type get () const {
return str;
}
template <typename T>
typename std::enable_if<std::is_same<T, int>::value, T>::type get () const {
return value;
}
private:
std::string str {"ZZZ"};
int value {45};
};
and usage would be like:
template <typename T>
void show (T v) {
std::cout << v << std::endl;
}
Foo f1;
show (f1.get<std::string> ());
show (f1.get<int> ());
Foo2 f2;
show (f2.get<std::string> ());
show (f2.get<int> ());
Foo3 f3;
show (f3.get<std::string> ());
show (f3.get<int> ());
Second option is helpful when you want to distinguish between two types. If you have more getters, then probably you will need to use first or third option.
I think it is better you define a getter and setter for each field. That is a better approach. It's easier to read and to understand and you achieve the same as with the template technique.
Explanation of your code:
It does not compile because of type checking. Template functions are generated when used in C++11. You use it with template parameter string so the function is generated. The problem is that you generate a function that returns T as a string, but you have code in your function that returns int (variable amin). Generate the function in your mind like so for T equals string:
string get_field(){
if(is_same<string,string>::value)
return pegah; // OK
else if(is_same<string,int> ::value)
return amin; // NOT OK, amin is of type int
}
One solution is that of M.M, it's called specialization. You specialize a template for (a) specific argument(s). And there are also other answers coming up.
I do not recommend that, because you finally do nothing else but generating getter functions for each variable in a specialized template. You could as well just have written:
string get_pegah(){ return pegah; }
int get_amin() { return amin; }
Easier to read, to maintain and straight forward. And more efficient I think.
as you see I want to use just one function
You don't really. You either call get_field<string> or get_field<int> and when called the appropriate function would be generated; either with T=string, T=int or both (depending on your use case). Though as you have learned by now, it's an error to do so in that case.
What you probably meant was that you want to have one function definition to do what you want. I don't think that is possible.