passing this as template argument - c++

I have two classes test1 and test2:
struct test1
{
int r;
test1() {}
test1(int value) : r(value) {}
test1 foo() const;
};
struct test2
{
int r;
test2() {}
test2(int value) : r(value) {}
};
template <typename t>
struct data_t
{
static const t one;
};
template <> const test1 data_t<test1>::one = test1(1);
template <> const test2 data_t<test2>::one = test2(1);
then i created a function to do somthing:
template <typename t, const t& value>
t do_somthing()
{ return value; };
the action of do_something is straightforward, it returns a copy of value, so in main function:
int main()
{
test1 r = do_somthing<test1, data_t<test1>::one>();
}
the problem happens when implementing test1::foo
test1 test1::foo() const
{ return do_somthing<test1, *this>(); }
the compiler stops with error:
'this' : can only be referenced inside non-static member functions
with *this it becomes test1 const& which acceptable as 2nd parameter, so why this error?

When you call a template method with explicit mention of parameters like,
do_somthing<test1, data_t<test1>::one>(); //(1) ok
do_somthing<test1, *this>(); // (2) error
then compiler expects that the explicit arguments should be compile time constants. In your (2)nd case, *this is not resolvable to a compile time constant, so you are getting the compiler error.
Change the definition to below:
template <typename t>
t do_somthing(const t& value)
{ return value; };
and now when you call as,
do_somthing<test1>(*this); // (2) ok
it should work. Because, now const t& doesn't need to be a compile time constant, even though it's resolved at compile time.

The compiler tells you exactly why this won't work, 'this' : can only be referenced inside non-static member functions. It's not usable in any other context.
If you want to templatize this function in this manner you have to use a template function that has the ability to deduce the argument type at compile time, like this:
template <class T>
T copy_value(const T& value)
{
return value;
}
class A
{
public:
A clone()
{
return copy_value(*this);
}
};
int main()
{
int x = 999;
int y = copy_value(x);
double d = 9.99;
double e = copy_value(d);
std::string s = "Test";
std::string t = copy_value(s);
return 0;
}
In each of the above examples, the function template is deduced at compile time so the compiler can properly generate the code necessary. Your classes that you use with this template should be appropriately copyable, and copy-constructable.

Related

C++ template argument limited to classes (not basic types)

Is it possible specify a template argument, that would never match to a basic type, such as an int? I'm heavily fighting ambiguities. So for example:
template<class T> void Function(const T& x) { SetString(x.GetString()); };
That would work only if there's a method GetString in T, but if the compiler sees this function, it tries to uses it even if T is just int for example.
Method 1
You can use std::enable_if as shown below:
C++11
//this function template will not be used with fundamental types
template<class T> typename std::enable_if<!std::is_fundamental<T>::value>::type Function(const T& x)
{
SetString(x.GetString());
};
Demo
C++17
template<class T> typename std::enable_if_t<!std::is_fundamental_v<T>> Function(const T& x)
{
SetString(x.GetString());
};
Demo
Method 2
We can make use of SFINAE. Here we use decltype and the comma operator to define the return type of the function template.
//this function template will work if the class type has a const member function named GetString
template <typename T> auto Function (T const & x) -> decltype( x.GetString(), void())
{
SetString(x.GetString());
};
Demo
Here we've used trailing return type syntax to specify the return type of the function template.
If the problem i that int doesn't support a GetString() method, maybe instead of disable the function for fundamental types, you could enable it if (and only if) the template type has a GetString() const method accepting a call without arguments.
Observe that GetString() must be const, because Function() receive a const reference, so you can call GetString() inside Function() only if GetString() is a const method.
The following is a full compiling example. Observe the failure in the bar1 and bar2 cases
#include <string>
void SetString (std::string const &)
{ }
struct foo // class with a conformat GetString method
{ std::string GetString () const { return "abc"; } };
struct bar1 // class with a not conformant (not const) GetString method
{ std::string GetString () { return "123"; } };
struct bar2 // class with a not conformant (require a int) GetString method
{ std::string GetString (int) const { return "123"; } };
struct bar3 // class without a GetString method
{ };
template <typename T>
auto Function (T const & x) -> decltype( x.GetString(), void())
{ SetString(x.GetString()); }
int main()
{
Function(foo{}); // compile
// Function(bar1{}); // compilation error (GetString isn't const)
// Function(bar2{}); // compilation error (GetString require a int)
// Function(bar3{}); // compilation error (no GetString method)
// Function(0); // compilation error (no GetString method)
}

How to define and set a funtion pointer to a template class method

I need to set a function pointer variable which is a method of a template class X to a method of X.
Here is a simple example.
X.h:
template<typename T>
class X {
public:
typedef T (*valproc)(T v);
X(T v);
T add(T v);
T val;
valproc curproc;
};
X.cpp:
#include "X.h"
template<typename T>
X<T>::X(T v) : val(v) {
curproc = &X<T>::add;
}
template<typename T>
T X<T>::add(T v) {
return v+val;
}
int main (int iArgC, char *apArgV[]) {
X<int> *p = new X<int>(3);
return p->curproc(7);
}
When I compile this, I get an error:
$ g++ -c -g -Wall X.cpp
X.cpp: In instantiation of 'X<T>::X(T) [with T = int]':
X.cpp:15:29: required from here
X.cpp:5:13: error: cannot convert 'int (X<int>::*)(int)' to 'X<int>::valproc {aka int (*)(int)}' in assignment
curproc = &X<T>::add;
Apparently int (X< int >::* )(int) is not the same as int (*)(int)
How can I define the correct type?
X<int>::add is a non-static member function. That means that &X<int>::add has the type int(X<int>::*)(int): pointer to non static member function of X<int> taking a single int parameter and returning int. Such a pointer cannot be converted to int(*)(int).
int(X<int>::*)(int) is conceptually more similar to int(*)(X<int>*, int) than it is to int(*)(int) (though the implementation may actually be much different depending on the platform's calling convention or if inheritance is involved). It requires an extra hidden X<int>* parameter: the this pointer.
The easiest way to do what you want would be to use a wrapper method:
template<typename T>
class X {
public:
using valproc = T(X::*)(T v);
X(T v)
: val{v},
proc{&X::add}
{}
T add(T v) { return v + val; }
T curproc(T v) { return (this->*proc)(v); }
T val;
valproc proc;
};
Live Demo
The funky syntax (this->*proc)(i) says "call the member function pointed to by proc on the object pointed to by this with the parameter i".
#include <stdio.h>
template<typename T>
class X {
public:
X(T v);
T add(T v);
T val;
int (X::*curproc)(T v);
};
template<typename T>
X<T>::X(T v) : val(v) {
curproc = &X<T>::add;
}
template<typename T>
T X<T>::add(T v) {
return v+val;
}
int main()
{
printf("Hello World\n");
X<int> *p = new X<int>(3);
printf("%d\n", (p->*(p->curproc))(7));
}
Usualy template classes are defined in the header file.
You can find more information here:
Why can’t I separate the definition of my templates class from its declaration and put it inside a .cpp file?
How can I avoid linker errors with my template functions?
How does the C++ keyword export help with template linker errors?
Change
return p->curproc(7);
to
return (p->*(p->curproc))(7);
*(p->currproc) is the function pointer and that need to be called on p object pointer
For details
C++ function pointer (class member) to non-static member function

C++ template generalization for const type

I am doing a small research here, which requires at some stage, that I have different classes doing (or not doing) operation on some data, depending on its constness.
A small example is like this (http://coliru.stacked-crooked.com/a/75c29cddbe6d8ef6)
#include <iostream>
template <class T>
class funny
{
public:
funny(T& a) : v(a) {v -= 1; }
virtual ~funny() { v += 1; }
operator T() {return v;}
private:
T& v;
};
#define V(a) funny<decltype(a)>(a)
int main()
{
char t[] = "ABC"; // <-- HERE
if( V( t[0] ) == (char)'A')
{
std::cout << "Pass" << t[0];
}
else
{
std::cout << "No Pass" << t[0];
}
}
Now, comes the question:
if I modify the line marked <-- HERE to be
const char t[] = "ABC";
I get the following compilation error:
main.cpp: In instantiation of 'funny<T>::funny(T&) [with T = const char&]':
main.cpp:21:7: required from here
main.cpp:7:28: error: assignment of read-only location '((funny<const char&>*)this)->funny<const char&>::v'
funny(T& a) : v(a) {v -= 1; }
~~^~~~
main.cpp: In instantiation of 'funny<T>::~funny() [with T = const char&]':
main.cpp:21:7: required from here
main.cpp:8:27: error: assignment of read-only location '((funny<const char&>*)this)->funny<const char&>::v'
virtual ~funny() { v += 1; }
~~^~~~
Which is totally understandable, since I try to modify a constant. Compiler is right here. However, I really need this to work also for const data, so I tried to create a const specialization of the template:
template <class T>
class funny <T const>
{
public:
funny(const T& a) : v(a) {}
operator T() {return v;}
private:
const T& v;
};
But regardless, the compiler does not find it, and still tries to compile the non-const version.
Any ideas on how to make this happen?
decltype(t[0]) deduces to const char&, which doesn't match your const char specialization. You have two options:
1) Change your specialization to template <class T> class funny <T const&>. That will work for this case, but won't work for const int FOO = 42; V(FOO);.
2) Change your V macro to always deduce to a non-reference type:
#define V(a) funny<typename std::remove_reference<decltype(a)>::type>(a)
Compiles if you change:
template <class T>
class funny <T const>
to:
template <class T>
class funny <const T&>

Passing member function (non-static) as a parameter to template function

I am trying to define a pointer to non-static member function, and pass the pointer along with class object to a template function, which will again send the member function for template struct operation. It keeps giving me type mismatch errors. Please help!
Clarify: 'vecfunc' is a non-static member function of class PTSolver. It takes as input vector and outputs vector. I want to pass a pointer to this vecfunc as a parameter to template function 'newt', which will also pass down to the template struct operation 'fmin().' All throughout the passing processes, I need to give information about PTSolver object 'ptsolver' since it's not a static member function. But I am not able to do this...
template <class T>
struct NRfmin {
VecDoub fvec;
T &func;
int n;
NRfmin(T &funcc) : func(funcc) {}
double operator() (VecDoub_I &x) {
n=x.size();
double sum=0.0;
fvec=func(x);
for (int i = 0;i<n;i++) sum += SQR(fvec[i]);
return 0.5*sum;
}
};
template <class T>
void newt(VecDoub_IO &x, bool &check, T &vecfunc, PTSolver &obj){
NRfmin<T> fmin(obj.*vecfunc);
VecDoub &fvec=fmin.fvec;
f=fmin(x);
...
}
class PTSolver {
public:
PTSolver() = default;
virtual ~PTSolver() = default;
void solve();
VecDoub vecfunc(VecDoub_I);
};
VecDoub PTSolver::vecfunc(VecDoub_I x) {
int n=x.size();
VecDoub results(n);
for (int i=0;i<n;i++) {
results[i]=2.0*x[i];
}
return results;
}
int main() {
VecDoub initGuess(2);
initGuess[0]=4.4;
initGuess[1]=5.5;
bool check;
//function<VecDoub(PTSolver*, VecDoub_I)> Func=&PTSolver::vecfunc;
typedef VecDoub (PTSolver::*PMemFnc)(VecDoub_I x);
PMemFnc Func;
PTSolver ptsolver;
newt<PMemFnc>(initGuess, check, Func, ptsolver);
return 0;
}
You have a type mismatch:
template <class T>
struct NRfmin {
NRfmin(T &funcc) : func(funcc) {}
};
template <class T>
void newt(VecDoub_IO &x, bool &check, T &vecfunc, PTSolver &obj){
NRfmin<T> fmin(obj.*vecfunc);
..
};
In both cases T is a pointer to member function, but you're constructing fmin with something that is definitely not a T& (it isn't even a valid expression). Either you meant to just forward the pointer, in which case:
NRfmin<T> fmin(vecfunc);
Or you want to pass NRfmin a bound functor.

How do I avoid implicit conversions on non-constructing functions?

How do I avoid implicit casting on non-constructing functions?
I have a function that takes an integer as a parameter,
but that function will also take characters, bools, and longs.
I believe it does this by implicitly casting them.
How can I avoid this so that the function only accepts parameters of a matching type, and will refuse to compile otherwise?
There is a keyword "explicit" but it does not work on non-constructing functions. :\
what do I do?
The following program compiles, although I'd like it not to:
#include <cstdlib>
//the function signature requires an int
void function(int i);
int main(){
int i{5};
function(i); //<- this is acceptable
char c{'a'};
function(c); //<- I would NOT like this to compile
return EXIT_SUCCESS;
}
void function(int i){return;}
*please be sure to point out any misuse of terminology and assumptions
Define function template which matches all other types:
void function(int); // this will be selected for int only
template <class T>
void function(T) = delete; // C++11
This is because non-template functions with direct matching are always considered first. Then the function template with direct match are considered - so never function<int> will be used. But for anything else, like char, function<char> will be used - and this gives your compilation errrors:
void function(int) {}
template <class T>
void function(T) = delete; // C++11
int main() {
function(1);
function(char(1)); // line 12
}
ERRORS:
prog.cpp: In function 'int main()':
prog.cpp:4:6: error: deleted function 'void function(T) [with T = char]'
prog.cpp:12:20: error: used here
This is C++03 way:
// because this ugly code will give you compilation error for all other types
class DeleteOverload
{
private:
DeleteOverload(void*);
};
template <class T>
void function(T a, DeleteOverload = 0);
void function(int a)
{}
You can't directly, because a char automatically gets promoted to int.
You can resort to a trick though: create a function that takes a char as parameter and don't implement it. It will compile, but you'll get a linker error:
void function(int i)
{
}
void function(char i);
//or, in C++11
void function(char i) = delete;
Calling the function with a char parameter will break the build.
See http://ideone.com/2SRdM
Terminology: non-construcing functions? Do you mean a function that is not a constructor?
8 years later (PRE-C++20, see edit):
The most modern solution, if you don't mind template functions -which you may mind-, is to use a templated function with std::enable_if and std::is_same.
Namely:
// Where we want to only take int
template <class T, std::enable_if_t<std::is_same_v<T,int>,bool> = false>
void func(T x) {
}
EDIT (c++20)
I've recently switched to c++20 and I believe that there is a better way. If your team or you don't use c++20, or are not familiar with the new concepts library, do not use this. This is much nicer and the intended method as outlines in the new c++20 standard, and by the writers of the new feature (read a papers written by Bjarne Stroustrup here.
template <class T>
requires std::same_as(T,int)
void func(T x) {
//...
}
Small Edit (different pattern for concepts)
The following is a much better way, because it explains your reason, to have an explicit int. If you are doing this frequently, and would like a good pattern, I would do the following:
template <class T>
concept explicit_int = std::same_as<T,int>;
template <explicit_int T>
void func(T x) {
}
Small edit 2 (the last I promise)
Also a way to accomplish this possibility:
template <class T>
concept explicit_int = std::same_as<T,int>;
void func(explicit_int auto x) {
}
Here's a general solution that causes an error at compile time if function is called with anything but an int
template <typename T>
struct is_int { static const bool value = false; };
template <>
struct is_int<int> { static const bool value = true; };
template <typename T>
void function(T i) {
static_assert(is_int<T>::value, "argument is not int");
return;
}
int main() {
int i = 5;
char c = 'a';
function(i);
//function(c);
return 0;
}
It works by allowing any type for the argument to function but using is_int as a type-level predicate. The generic implementation of is_int has a false value but the explicit specialization for the int type has value true so that the static assert guarantees that the argument has exactly type int otherwise there is a compile error.
Maybe you can use a struct to make the second function private:
#include <cstdlib>
struct NoCast {
static void function(int i);
private:
static void function(char c);
};
int main(){
int i(5);
NoCast::function(i); //<- this is acceptable
char c('a');
NoCast::function(c); //<- Error
return EXIT_SUCCESS;
}
void NoCast::function(int i){return;}
This won't compile:
prog.cpp: In function ‘int main()’:
prog.cpp:7: error: ‘static void NoCast::function(char)’ is private
prog.cpp:16: error: within this context
For C++14 (and I believe C++11), you can disable copy constructors by overloading rvalue-references as well:
Example:
Say you have a base Binding<C> class, where C is either the base Constraint class, or an inherited class. Say you are storing Binding<C> by value in a vector, and you pass a reference to the binding and you wish to ensure that you do not cause an implicit copy.
You may do so by deleting func(Binding<C>&& x) (per PiotrNycz's example) for rvalue-reference specific cases.
Snippet:
template<typename T>
void overload_info(const T& x) {
cout << "overload: " << "const " << name_trait<T>::name() << "&" << endl;
}
template<typename T>
void overload_info(T&& x) {
cout << "overload: " << name_trait<T>::name() << "&&" << endl;
}
template<typename T>
void disable_implicit_copy(T&& x) = delete;
template<typename T>
void disable_implicit_copy(const T& x) {
cout << "[valid] ";
overload_info<T>(x);
}
...
int main() {
Constraint c;
LinearConstraint lc(1);
Binding<Constraint> bc(&c, {});
Binding<LinearConstraint> blc(&lc, {});
CALL(overload_info<Binding<Constraint>>(bc));
CALL(overload_info<Binding<LinearConstraint>>(blc));
CALL(overload_info<Binding<Constraint>>(blc));
CALL(disable_implicit_copy<Binding<Constraint>>(bc));
// // Causes desired error
// CALL(disable_implicit_copy<Binding<Constraint>>(blc));
}
Output:
>>> overload_info(bc)
overload: T&&
>>> overload_info<Binding<Constraint>>(bc)
overload: const Binding<Constraint>&
>>> overload_info<Binding<LinearConstraint>>(blc)
overload: const Binding<LinearConstraint>&
>>> overload_info<Binding<Constraint>>(blc)
implicit copy: Binding<LinearConstraint> -> Binding<Constraint>
overload: Binding<Constraint>&&
>>> disable_implicit_copy<Binding<Constraint>>(bc)
[valid] overload: const Binding<Constraint>&
Error (with clang-3.9 in bazel, when offending line is uncommented):
cpp_quick/prevent_implicit_conversion.cc:116:8: error: call to deleted function 'disable_implicit_copy'
CALL(disable_implicit_copy<Binding<Constraint>>(blc));
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Full Source Code: prevent_implicit_conversion.cc
Well, I was going to answer this with the code below, but even though it works with Visual C++, in the sense of producing the desired compilation error, MinGW g++ 4.7.1 accepts it, and invokes the rvalue reference constructor!
I think it must be a compiler bug, but I could be wrong, so – anyone?
Anyway, here's the code, which may turn out to be a standard-compliant solution (or, it may turn out that that's a thinko on my part!):
#include <iostream>
#include <utility> // std::is_same, std::enable_if
using namespace std;
template< class Type >
struct Boxed
{
Type value;
template< class Arg >
Boxed(
Arg const& v,
typename enable_if< is_same< Type, Arg >::value, Arg >::type* = 0
)
: value( v )
{
wcout << "Generic!" << endl;
}
Boxed( Type&& v ): value( move( v ) )
{
wcout << "Rvalue!" << endl;
}
};
void function( Boxed< int > v ) {}
int main()
{
int i = 5;
function( i ); //<- this is acceptable
char c = 'a';
function( c ); //<- I would NOT like this to compile
}
I first tried PiotrNycz's approach (for C++03, which I'm forced to use for a project), then I tried to find a more general approach and came up with this ForcedType<T> template class.
template <typename T>
struct ForcedType {
ForcedType(T v): m_v(v) {}
operator T&() { return m_v; }
operator const T&() const { return m_v; }
private:
template <typename T2>
ForcedType(T2);
T m_v;
};
template <typename T>
struct ForcedType<const T&> {
ForcedType(const T& v): m_v(v) {}
operator const T&() const { return m_v; }
private:
template <typename T2>
ForcedType(const T2&);
const T& m_v;
};
template <typename T>
struct ForcedType<T&> {
ForcedType(T& v): m_v(v) {}
operator T&() { return m_v; }
operator const T&() const { return m_v; }
private:
template <typename T2>
ForcedType(T2&);
T& m_v;
};
If I'm not mistaken, those three specializations should cover all common use cases. I'm not sure if a specialization for rvalue-reference (on C++11 onwards) is actually needed or the by-value one suffices.
One would use it like this, in case of a function with 3 parameters whose 3rd parameter doesn't allow implicit conversions:
function(ParamType1 param1, ParamType2 param2, ForcedType<ParamType3> param3);