template specialization sub class - c++

I have a problem that can be minimized to the following example
#include <iostream>
#include <string>
class A{
public:
const char* chr;
A(){chr = "aaa";}
};
class B : A{
public:
const char* chr;
B(){chr = "bbb";}
};
template <class T>
std::string to_str(T) = delete;
template<>
inline std::string
to_str<A>(A object) {
std::string str;
return str.assign((object.chr));
}
int main() {
A a;
B b;
std::cout << to_str(b) << std::endl;
}
when changing it to std::cout << to_str(a) << std::endl; the code runs and prints 'aaa', but like this, it stops at compilation and outputs
main.cpp: In function 'int main()':
main.cpp:30:24: error: use of deleted function 'std::__cxx11::string to_str(T) [with T = B; std::__cxx11::string = std::__cxx11::basic_string<char>]'
std::cout << to_str(b) << std::endl;
^
main.cpp:18:13: note: declared here
std::string to_str(T) = delete;
^~~~~~
exit status 1
now lets say i have a lot of classes that inherit A, can i 'tell' the compiler they all can go to the same function (the one accepts A)?
Thanks.

can i 'tell' the compiler they all can go to the same function(the one accepts A)?
Yes, using SFINAE and std::is_base_of
template <typename T>
typename std::enable_if<std::is_base_of<A, T>::value, std::string>::type
to_str (T const & t)
{ return t.chr; }
The following is a full working example
#include <type_traits>
#include <iostream>
#include <string>
struct A { char const * chr; A() : chr{"aaa"} {} };
struct B : A { char const * chr; B() : chr{"bbb"} {} };
struct C { char const * chr; C() : chr{"ccc"} {} };
template <typename T>
typename std::enable_if<std::is_base_of<A, T>::value, std::string>::type
to_str (T const & t)
{ return t.chr; }
int main()
{
A a;
B b;
C c;
std::cout << to_str(a) << std::endl; // print aaa
std::cout << to_str(b) << std::endl; // print bbb
// std::cout << to_str(c) << std::endl; // compilation error
}

I question if this really is a minimized example of your problem. I think that what's happened is that some important details got lost in the translation, because the code you've shown us here has a number of issues.
B inherits privately from A. There is no way we can really treat a B like an A in this case.
If you changed inheritance to public, then we could attempt to force a B in like so:
class B : public A{/*...*/};
// ...
std::cout << to_str(*static_cast<A*>(&b)) << std::endl;
But the output will remain "aaa", which leads me to my next points
Your to_str specialization for A accepts by value. This is important because even if we wanted to force a B in, we end up slicing the object, this matters because
B redefines the const char* chr effectively hiding A::chr, and since we've sliced, there's no way to recover B's chr.
We could start fixing things but first fixing the slicing by accepting A by reference instead (or const reference), and always preferring an overload instead of a template specialization for a function:
std::string to_str(A& object) {/*...*/}
The next problem is that there is no way direct to recover B's chr from an instance of A. We could go one of two ways here.
Use a std::string member in A and do not redeclare it in any derived class, then derived classes can set it on initialization.
Example:
class A{
public:
std::string chr;
A():chr{"aaa"}{}
};
class B : public A{
public:
B(){chr = "bbb";}
};
We write a virtual const char* get_char() method in A that derived classes can override.
Example:
class A{
public:
const char* chr;
A(){chr = "aaa";}
virtual const char* get_chr() const{return chr;}
};
class B : public A{
public:
const char* chr;
B(){chr = "bbb";}
const char* get_chr() const override {return chr;}
};
template <class T>
std::string to_str(T) = delete;
std::string to_str(A& object) {
std::string str;
return str.assign((object.get_chr()));
// ...
std::cout << to_str(*static_cast<A*>(&b)) << std::endl;
Note that at this point we're still forcing each B to be an A, which leads me to my next point
template <class T> std::string to_str(T) = delete; will always exactly match every type you don't explicitly specialize for, being preferred in the worst case and causing ambiguity in the best case.
If you don't have any control over this function, then we're stuck with what we've got. However, if we do, then we can achieve what we need using type_traits to accept anything that is derived from A.
In this way we can keep your private inheritance, and also keep your redeclared chr member, while simultaneously disabling to_str for everything else and not requiring we static_cast our b.
Example:
#include <type_traits>
class A{
public:
const char* chr;
A(){chr = "aaa";}
};
class B : A{
public:
const char* chr;
B(){chr = "bbb";}
};
template<class T, class = std::enable_if_t<std::is_base_of<A, T>::value, int>>
inline std::string to_str(T& object) {
std::string str;
return str.assign((object.chr));
}
int main() {
A a;
B b;
std::cout << to_str(b) << std::endl;
}
Overall, I think that the best approach would be to give A a protected std::string chr that each derived class sets on initialization, and then have your to_string function that is specialized for A& (as an overload) print that member.
Edit: I forgot one last note. Issue #6: There are no virtual members in A. Therefore you will never be able to dynamic_cast a pointer to A to any derived class.

Template function specialization does not work that way. There is no overload resolution; it merely permits replacing a specific function body with specific template arguments with your specialized one. It is rarely useful.
What you want is overload resolution, possibly with tag dispatch.
First remove this completely:
template <class T>
std::string to_str(T) = delete;
next, write an overload:
inline std::string to_str(A object) {
std::string str;
return str.assign((object.chr));
}
and done. Overload resolution dispatches B to the A overload.
Your next problem is slicing. B has two members named chr: A::chr and B::chr. For no good reason. In addition you are needlessly copying A (or the A subobject of B).
inline std::string to_str(A const& object) {
std::string str;
return str.assign((object.chr));
}
this avoids a needless copy of A.
class A{
public:
const char* chr;
A(){chr = "aaa";}
};
class B : public A{ // public, not private
public:
// const char* chr; // no need for this
B(){chr = "bbb";}
};

According to 14.7.3 [temp.expl.spec] paragraph 1, only non-deleted function templates may be explicitly specialized
C++ Standard Core Language Defect Reports and Accepted Issues, Revision 97
So, if you change
template <class T>
std::string to_str(T) = delete;
in, for example,
template <class T>
std::string to_str(T) { return ""; }
everything should work

Related

Problem with operator+ of templated inherited class [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 last month.
Improve this question
I am trying to figure a problem with a piece of code that I wrote.
I have two structs (bar and foo) that can be used to contruct a templated class myClass.
For this example, the structs will contain information about the size of a vector of a templated quantity (called baseType).
There is also a third struct called infoClass which will contain some information about the object, e.g., its name.
The class myClass will inherite from infoClass and from either bar or foo.
When I write the operator+ for myClass, the compiler is allowing me to do:
myClass<double, foo> = myClass<double, bar> + myClass<double, bar>;
I was able to track the problem to the constructor myClass (const infoClass& obj).
If I put an extra parameter I will get the error I am expecting saying:
error: conversion from ‘myClass<[...],bar>’ to non-scalar type ‘myClass<[...],foo>’ requested
However, I am not understanding why do I need to put an extra parameter in the constructor for the code to work as expected.
Can anyone shed some light on this?
I have the following code:
#include <iostream>
#include <vector>
struct bar
{
int size{10};
};
struct foo
{
int size{15};
};
struct infoClass
{
std::string name;
};
template<typename baseType, typename myType>
class myClass;
typedef myClass<double, bar> doubleBar;
typedef myClass<double, foo> doubleFoo;
template<typename baseType, typename myType>
class myClass
:
public infoClass,
public myType
{
private:
std::vector<baseType> data_;
public:
myClass(double initValue) : data_(this->size,{initValue}){}
myClass (const infoClass& obj) // myClass (const infoClass& obj, double someVar) //this works
:
data_(this->size,{0})
{
this->name = obj.name;
}
std::vector<baseType>& data() {return data_;}
const std::vector<baseType>& data() const {return data_;}
};
template<typename baseType, typename myType>
myClass<baseType, myType> operator+(const myClass<baseType, myType>& obj1, const myClass<baseType, myType>& obj2)
{
if(obj1.data().size() != obj2.data().size())
std::cout << "error, sizes are different" << std::endl;
myClass<baseType, myType> result(0);
for(int i=0; i < obj1.data().size(); i++)
{
result.data()[i] = obj1.data()[i] + obj2.data()[i];
}
return result;
}
int main()
{
doubleBar a(3);
doubleBar b(4);
doubleBar c = a + b;
doubleFoo e = a + a;
std::cout << "End" << std::endl;
return 0;
}
You problem is indeed in myClass (const infoClass& obj) constructor. Such constructor is called "converting construcor" and can be used by compiler to implicitly convert one type to another.
Since both of you types doubleBar and doubleFoo can be implicitly converted to infoClass comlpiler then can convert it back to either of these classes. To prevent this implicit behavior just add keyword explicit in this constructor declaration, i.e.:
explicit myClass (const infoClass& obj)
This will tell compiler not to use this constructor for implicit conversion and everything will work as you expect.

How to pass std::function as an argument to a mocked method in gmock?

I am getting a runtime error when trying to pass an std:function as an argument to a mocked method inside EXPECT_CALL.
I wish to verify that Bar is called with callback as an argument.
Code:
#include <gtest/gtest.h>
#include <gmock/gmock.h>
class Foo {
public:
virtual void Bar(const std::function<void (const std::string &name)> &callback) = 0;
};
class MockFoo : public Foo {
public:
MOCK_METHOD(void, Bar, (const std::function<void (const std::string &name)> &callback));
};
TEST(FooBarTest, callback) {
MockFoo foo;
const std::function<void(const std::string &name)> callback;
EXPECT_CALL(foo, Bar(callback)).Times(1);
foo.Bar(callback);
}
int main(int argc, char **argv) {
testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}
An error is produced at runtime:
/usr/local/include/gtest/gtest-matchers.h:211:60: error: no match for ‘operator==’ (operand types are ‘const std::function<void(const std::__cxx11::basic_string<char>&)>’ and ‘const std::function<void(const std::__cxx11::basic_string<char>&)>’)
bool operator()(const A& a, const B& b) const { return a == b; }
There are pre-defined ACTIONS that you could use for this purpose. Your EXPECT_CALL would look something like:
using namespace testing; // for brevity
TEST(FooBarTest, callback) {
MockFoo foo;
const std::function<void(const std::string &name)> callback;
EXPECT_CALL(foo, Bar(_)).WillOnce(Invoke(callback));
foo.Bar(callback);
}
As pointed out by #IanGralinski, there's no matcher for std::function, so you can use any matcher for the call (i.e. _).
However, this is not how I would use gmock here - why mocking Foo if you use it directly? Usually mocks are used when you test interactions of your (real) class with other classes (mocked). So in your example: Foo could be mocked by MockFoo and used by some other class (real one), using dependency injection.
On a side note, remember to add virtual destructor to Foo if the object derived from Foo is to be deleted by pointer to Foo (this would be UB without virtual dtor).
The arguments to the method named in an EXPECT_CALL are actually matchers. When you just provide a value (something which is not already a gmock Matcher<T> type), that implies an Eq matcher. So EXPECT_CALL(foo, Bar(callback)) really means EXPECT_CALL(foo, Bar(Eq(callback))). The trouble is, std::function does not provide an operator== for comparing two functions. Its type-erasure properties mean an equality test would be impossible to implement in general, plus of course some of the class functor types it might wrap around won't have their own operator== either.
But it is possible to test whether a std::function contains a very specific object. If you don't want to just ignore the argument by expecting Bar(_), here's an idea for identifying whether a std::function is a specific dummy function.
First, create a callable class which we'll use to initialize the std::function object. I'll also have its operator() call a mock method, which is not needed when it's just passed to a mock function, but this will make it possible to use the same std::function in different contexts, or set expectations before one real function which will both call it directly and pass it to a mocked interface.
template <typename FuncT> class DummyFunction; // undefined
template <typename RetType, typename... ArgTypes>
class DummyFunction<RetType(ArgTypes...)> {
public:
constexpr DummyFunction() : DummyFunction(0) {}
explicit constexpr DummyFunction(int key) : m_key(key) {}
constexpr DummyFunction(const DummyFunction& f) : m_key(f.m_key) {}
constexpr int key() const { return m_key; }
MOCK_METHOD(RetType, doCall, (ArgTypes...));
RetType operator()(ArgTypes... args)
{ return doCall(std::forward<ArgTypes>(args)...); }
friend constexpr bool operator==(const DummyFunction& f1, const DummyFunction& f2)
{ return f1.m_key == f2.m_key; }
friend constexpr bool operator!=(const DummyFunction& f1, const DummyFunction& f2)
{ return !(f1 == f2); }
friend std::ostream& operator<<(std::ostream& os, const DummyFunction& f)
{ return os << "DummyFunction(" << f.m_key << ")"; }
private:
int m_key;
};
Then a gmock Matcher to test whether a std::function contains a DummyFunction object with the exact same function type as template parameter and the same key as a given DummyFunction object could look like this. Since it's possible to convert one type of std::function to another as long as the parameter types and return types convert correctly (or the return type changes to void), I made it a "polymorphic" matcher which accepts any std::function specialization for testing.
template <class DummyFuncType>
class IsDummyFunctionTester {
public:
explicit constexpr IsDummyFunctionTester(int key) : m_key(key) {}
// The three member functions required for gmock "PolymorphicMatcher":
template <typename FuncType>
bool MatchAndExplain(const std::function<FuncType>& f,
::testing::MatchResultListener* listener) const {
bool type_ok = f.target_type() == typeid(DummyFuncType);
if (type_ok) {
int f_key = f.template target<DummyFuncType>()->key();
if (f_key == m_key) return true;
*listener << "std::function contains DummyFunction(" << m_key << ")";
} else if (!f) {
*listener << "std::function is empty";
} else {
// Note name() is implementation dependent. For g++/clang it's mangled.
*listener << "std::function target's type_info::name() is "
<< f.target_type().name();
}
return false;
}
void DescribeTo(std::ostream* os) const
{ *os << "is a DummyFunction(" << m_key << ")"; }
void DescribeNegationTo(std::ostream* os) const
{ *os << "is not a DummyFunction(" << m_key << ")"; }
private:
int m_key;
};
template <typename FuncType>
decltype(auto) StdFuncIsDummyFunc(const DummyFunction<FuncType>& f) {
return ::testing::MakePolymorphicMatcher(
IsDummyFunctionTester<DummyFunction<FuncType>>(f.key()));
}
So finally, you can do:
TEST(FooBarTest, callback) {
MockFoo foo;
const DummyFunction<void(const std::string &name)> callback;
EXPECT_CALL(foo, Bar(StdFuncIsDummyFunc(callback))).Times(1);
foo.Bar(callback);
}
If you have just one DummyFunction, or if exactly which DummyFunction is which isn't important for the test, you can just use the default "key" of zero like above. Otherwise, you can specify unique keys for each distinct dummy callback.

My lambda does not correctly convert the captured 'this' during copy construction

I've narrowed down my problem to exactly this
#include <iostream>
#include <functional>
struct Foo {
std::function<Foo*()> lambda;
Foo()
:lambda([this](){return this;})
{}
};
int main(){
Foo a;
Foo b = a;
std::cout << &a << " " << a.lambda() << std::endl;
std::cout << &b << " " << b.lambda() << std::endl;
}
where the output is
0x7ffd9128b8a0 0x7ffd9128b8a0
0x7ffd9128b880 0x7ffd9128b8a0
I originally expected that this would always point to the instance that owned the lambda. However I forgot about copy construction. In this case the lambda captures this and then it is fixed and no matter how many times the lambda is copied it points to the original value of this.
Is there a way fix this so that lambda always has a reference to it's owning object this even under copy construction of the owning object.
Sounds like you need to provide your own special member functions, no? E.g., for the copy constructor:
Foo(const Foo& other)
:lambda([this](){return this;})
{}
Whilst #lubgr answered the question for what I asked I think it is worth noting the other solution I have for my exact problem. The question stemmed from building a class to encapsulate lazy initialisation of members. My original attempt was
template <typename T>
class Lazy {
mutable boost::once_flag _once;
mutable boost::optional<T> _data;
std::function<T()> _factory;
void Init() const { boost::call_once([&] { _data = _factory(); }, _once); }
public:
explicit Lazy(std::function<T()> factory):_once(BOOST_ONCE_INIT),_factory(factory){}
T& Value() {
Init();
return *_data;
}
};
which can be used like
class Foo {
int _a;
Lazy<int> _val;
Foo(a):_a(a):_val([this](){return this->_a+1;}){}
}
Foo f(10);
int val = f._val.Value();
but has the same problem that I asked in my question in that this is a circular reference that doesn't get preserved for copy construction. The solution is not to create a custom copy constructor and possibly move constructor but to fix the Lazy implementation class so that we can pass in an arg to the factory.
The new implementation of Lazy for members is
template <typename T, typename TThis>
class LazyMember {
mutable boost::once_flag _once;
mutable boost::optional<T> _data;
typedef std::function<T(TThis const*)> FactoryFn;
FactoryFn _factory;
void Init(TThis const * arg0) const { boost::call_once([&] { _data = _factory(arg0); }, _once); }
public:
explicit LazyMember(FactoryFn factory):_once(BOOST_ONCE_INIT),_factory(factory){}
T& Value(TThis const * arg0) { Init(arg0); return *_data; }
T const & Value(TThis const * arg0) const { Init(arg0); return *_data; }
};
which is used as
class Foo {
int _a;
Lazy<int> _val;
Foo(a):_a(a):_val([](Foo const * _this){return _this->_a+1;}){}
}
Foo f(10);
int val = f._val.Value(&f);
and this doesn't have the circular reference problems and thus doesn't require a custom copy/move constructor.

Alternative to overloading functions with derived types

Sorry for the uninformative title, I don't really know what to call what I am asking.
I want to achieve the following: Having a container of a base class type with instances of derived types, accessing the containers and calling a function overload dependent on the type of the derived object accessed. In a question earlier I asked here I learned that the static design I had in mind so far, does not work. The way I tried is this:
struct Int2TypeBase{
};
template <int v>
struct Int2Type : public Int2TypeBase
{
enum
{
value = v
};
};
void f(const Int2Type<0>&){
std::cout << "f(const Int2Type<0>&)" << "\n";
}
void f(const Int2Type<1>&){
std::cout << "f(const Int2Type<1>&)" << "\n";
}
int main(){
using namespace std;
std::vector<std::reference_wrapper<Int2TypeBase>> v;
Int2Type<0> i2t_1;
v.emplace_back(i2t_1);
Int2Type<1> i2t_2;
v.emplace_back(i2t_2);
auto x0 = v[0];
auto x1 = v[1];
f(x0.get()); // After my imagination this would have called void f(const Int2Type<0>&)
f(x1.get()); // After my imagination this would have called void f(const Int2Type<1>&)
}
Ok, so I want the correct overload of f to be selected, this however does not compile as at compile time it is unknown which type x0 and x1 actually have. But is there some alternate design that can realize this behavior?
Overloading is a static mechanism based on static types.
If you want to change behaviour dynamically based on the dynamic type of an object, C++ provides another built-in language feature for that: Virtual functions. Use them like this:
struct Int2TypeBase
{
virtual void do_f() = 0;
};
template <int v> struct Int2Type : Int2TypeBase
{
void do_f() override
{
// specific behaviour for Int2Type<v> goes here
}
/* ... */
};
void f(Int2TypeBase & x) { x.do_f(); }
Now you can call f on any base subobject and the correct behaviour is selected at runtime. In particular, f(x0.get()) and f(x1.get()) now select and dispatch to Int2Type<0>::do_f and Int2Type<1>::do_f at runtime, respectively.

Implicitly cast wrapper class to supperclass in templated call

In designing a DSL (which compiles into C++), I found it convenient to define a wrapper class that, uppon destruction, would call a .free() method on the contained class:
template<class T>
class freeOnDestroy : public T {
using T::T;
public:
operator T&() const { return *this; }
~freeOnDestroy() { T::free(); }
};
The wrapper is designed to be completely transparent: All methods, overloads and constructors are inherited from T (at least to my knowledge), but when included in the wrapper, the free() method is called uppon destruction. Note that I explicitly avoid using T's destructor for this since T::free() and ~T() may have different semantics!
All this works fine, untill a wrapped class gets used as a member to a non-reference templated call, at which point freeOnDestroy is instantiated, calling free on the wrapped object. What I would like to happen is for the tempated method to use T instead of freeOnDestroy<T>, and to implicitly cast the parameter into the supperclass. The following code sample illustrates this problem:
// First class that has a free (and will be used in foo)
class C{
int * arr;
public:
C(int size){
arr = new int[size];
for (int i = 0; i < size; i++) arr[i] = i;
}
int operator[] (int idx) { return arr[idx]; }
void free(){ cout << "free called!\n"; delete []arr; }
};
// Second class that has a free (and is also used in foo)
class V{
int cval;
public:
V(int cval) : cval(cval) {}
int operator[] (int idx) { return cval; }
void free(){}
};
// Foo: in this case, accepts anything with operator[int]
// Foo cannot be assumed to be written as T &in!
// Foo in actuality may have many differently-templated parameters, not just one
template<typename T>
void foo(T in){
for(int i = 0; i < 5; i++) cout << in[i] << ' ';
cout << '\n';
}
int main(void){
C c(15);
V v(1);
freeOnDestroy<C> f_c(15);
foo(c); // OK!
foo(v); // OK!
foo<C>(f_c); // OK, but the base (C) of f_c may not be explicitly known at the call site, for example, if f_c is itself received as a template
foo(f_c); // BAD: Creates a new freeOnDestroy<C> by implicit copy constructor, and uppon completion calls C::free, deleting arr! Would prefer it call foo<C>
foo(f_c); // OH NO! Tries to print arr, but it has been deleted by previous call! Segmentation fault :(
return 0;
}
A few non solutions I should mention are:
Making freeOnDestroy::freeOnDestroy(const freeOnDestroy &src) explicit and private, but this seems to override T's constructor. I'd hoped it would try to implicitly convert it to T and use that as the template argument.
Assume foo receives a reference of its templated arguments (as in void foo(T &in): This is neither the case, nor desirable in some cases
Always explicitly template the call to foo, as in foo<C>(f_c): f_c itself may be templated, so it's hard to know to instantiate foo with C (yes, this could be done with creating multiple versions of foo, to remove the wrappers one by one, but I can't find a way of doing that without creating a different overload for each templated argument of foo).
In summary, my question is: Is there a clean(ish) method to ensure a base class will be casted to its superclass when resolving a template? Or, if not, is there some way of using SFINAE, by causing a substitution failure when the template argument is an instance of the wrapper class, and thus force it to use the implicit cast to the wrapped class (without duplicating each foo-like method signature possibly dozens of times)?
I presently have a work-arround that involves changes in the DSL, but I'm not entirely happy with it, and was curious if it was at all possible to design a wrapper class that works as described.
The problem here not when "wrapped class gets used as a member to a non-reference templated call".
The problem here is that the template wrapper -- and likely its superclass too -- has violated the Rule Of Three.
Passing an instance of the class as a non-reference parameter is just another way of saying "passing by value". Passing by value makes a copy of the instance of the class. Neither your template class -- nor its wrapped class, most likely -- has an explicit copy constructor; as such the copied instance of the class has no knowledge that it is a copy, hence the destructor does what it thinks it should do.
The correct solution here is not to hack something up that makes passing an instance of freeOnDestroy<T> by value end up copying T, rather than freeOnDestroy<T>. The correct solution is to add a proper copy-constructor and the assignment operator to both the freeOnDestroy template, and possibly any superclass that uses it, so that everything complies with the Rule Of Three.
You can use a properly defined detector and a sfinaed function, as it follows:
#include<iostream>
#include<type_traits>
template<class T>
class freeOnDestroy : public T {
using T::T;
public:
operator T&() const { return *this; }
~freeOnDestroy() { T::free(); }
};
template<typename T>
struct FreeOnDestroyDetector: std::false_type { };
template<typename T>
struct FreeOnDestroyDetector<freeOnDestroy<T>>: std::true_type { };
class C{
int * arr;
public:
C(int size){
arr = new int[size];
for (int i = 0; i < size; i++) arr[i] = i;
}
int operator[] (int idx) { return arr[idx]; }
void free(){ std::cout << "free called!\n"; delete []arr; }
};
class V{
int cval;
public:
V(int cval) : cval(cval) {}
int operator[] (int idx) { return cval; }
void free(){}
};
template<typename..., typename T>
std::enable_if_t<not FreeOnDestroyDetector<std::decay_t<T>>::value>
foo(T in) {
std::cout << "here you have not a freeOnDestroy based class" << std::endl;
}
template<typename..., typename T>
std::enable_if_t<FreeOnDestroyDetector<std::decay_t<T>>::value>
foo(T &in) {
std::cout << "here you have a freeOnDestroy based class" << std::endl;
}
int main(void){
C c(15);
V v(1);
freeOnDestroy<C> f_c(15);
foo(c);
foo(v);
foo<C>(f_c);
foo(f_c);
foo(f_c);
return 0;
}
As you can see by running the example, free is called only once, that is for the freeOnDestroy created in the main function.
If you want to forbid definitely freeOnDestroy as a parameter, you can use a single function as the following one:
template<typename..., typename T>
void foo(T &in) {
static_assert(not FreeOnDestroyDetector<std::decay_t<T>>::value, "!");
std::cout << "here you have a freeOnDestroy based class" << std::endl;
}
Note that I added a variadic parameter as a guard, so that one can no longer use foo<C>(f_c); to force a type to be used.
Remove it if you want to allow such an expression. It was not clear from the question.
One solution, which, although a little ugly, seems to work, is to use an overloaded unwrapping method, such as:
template<typename T> T freeOnDestroyUnwrapper(const T &in){ return in; }
template<typename T> T freeOnDestroyUnwrapper(const freeOnDestroy<T> &in){ return in; }
template<typename T> T freeOnDestroyUnwrapper(const freeOnDestroy<typename std::decay<T>::type> &in){ return in; }
template<typename T> T& freeOnDestroyUnwrapper(T &in){ return in; }
template<typename T> T& freeOnDestroyUnwrapper(freeOnDestroy<T> &in){ return in; }
template<typename T> T& freeOnDestroyUnwrapper(freeOnDestroy<typename std::decay<T>::type> &in){ return in; }
Then, calls can be made using the unwrapper:
int main(void){
C c(15);
V v(1);
freeOnDestroy<C> f_c(15);
foo(freeOnDestroyUnwrapper(c));
foo(freeOnDestroyUnwrapper(v));
foo<C>(freeOnDestroyUnwrapper(f_c));
foo(freeOnDestroyUnwrapper(f_c));
foo(freeOnDestroyUnwrapper(f_c));
return 0;
}
Or, to make this less verbose, we can alter foo so it does this for us:
template<typename T>
void _foo(T in){
for(int i = 0; i < 5; i++) cout << in[i] << ' ';
cout << '\n';
}
template<typename... Ts>
void foo(Ts&&... args){
_foo(freeOnDestroyUnwrapper(args)...);
}
And then call it as normal:
int main(void){
C c(15);
V v(1);
freeOnDestroy<C> f_c(15);
foo(c);
foo(v);
//foo<C>(f_c); // This now doesn't work!
foo(f_c);
foo(f_c);
return 0;
}
This seems to work for any number of arguments foo may have (of different templates, if needed), and seems to behave appropriately when foos input is a reference (which does not occur in my context, but would be good for the sake of making this solution generic).
I'm not convinced that this is the best solution, or that it generalizes to every case, plus, having to double all declarations is a bit cumbersome, and opaque to most IDEs autocomplete features. Better solutions and improvements are welcome!