equal_to usage in C++ template class - c++

I am confused on how to use this method. I tried the following:
std::equal_to(T objA, T objB);
I get errors if I use it like this. However, I have seen countless examples that use it like this:
pairs1 = mismatch(v1.begin(), v1.end(),
v2.begin(),
equal_to<int>());
How is this method supposed to be used?
Sample Error:
prog.cpp: In function ‘int main()’:
prog.cpp:25:31: error: no matching function for call to ‘std::equal_to<int>::equal_to(std::vector<int>&, std::vector<int>&)’
pairs1 = equal_to<int>(v2, v1));
^
In file included from /usr/include/c++/5/string:48:0,
from /usr/include/c++/5/random:40,
from /usr/include/c++/5/bits/stl_algo.h:66,
from /usr/include/c++/5/algorithm:62,
from prog.cpp:2:
/usr/include/c++/5/bits/stl_function.h:352:12: note: candidate: constexpr std::equal_to<int>::equal_to()
struct equal_to : public binary_function<_Tp, _Tp, bool>
^
/usr/include/c++/5/bits/stl_function.h:352:12: note: candidate expects 0 arguments, 2 provided
/usr/include/c++/5/bits/stl_function.h:352:12: note: candidate: constexpr std::equal_to<int>::equal_to(const std::equal_to<int>&)
/usr/include/c++/5/bits/stl_function.h:352:12: note: candidate expects 1 argument, 2 provided
/usr/include/c++/5/bits/stl_function.h:352:12: note: candidate: constexpr std::equal_to<int>::equal_to(std::equal_to<int>&&)
/usr/include/c++/5/bits/stl_function.h:352:12: note: candidate expects 1 argument, 2 provided

equal_to is not a function, you cannot call it directly like one. It's a class that has the operator() defined which means that you need to create an object and call operator() on that object.
Possible implementation:
template <class T = void>
struct equal_to {
constexpr bool operator()(const T& lhs, const T& rhs) const
{
return lhs == rhs;
}
};
Usage example:
auto test()
{
auto my_comp = equal_to<int>{};
bool b1 = my_comp(2, 3);
// or create a temporary object and call it in one line:
bool b2 = equal_to<int>{}(2, 3);
}
It also has a specialization that will deduce the arguments passed to operator():
template <>
struct equal_to<void> {
template <class T, class U>
constexpr auto operator()(T&& lhs, U&& rhs) const
-> decltype(std::forward<T>(lhs) == std::forward<U>(rhs))
{
return std::forward<T>(lhs) == std::forward<U>(rhs);
}
};
auto test2()
{
using namespace std::string_literals;
auto my_comp = equal_to<>{};
bool b1 = my_comp(2, 3);
bool b2 = my_comp("one string"s, "another string"s);
}

Related

Error with variadic templates function: candidate expects 0 arguments, 3 provided

I'm trying to write a static variadic templates constructor for my class. But I'm not so experienced in variadic templates and get an error.
I wrote the following code:
template <typename T> struct scalar {
template <typename... Args> static std::shared_ptr<scalar<T>> create(Args &&...args) {
return std::make_shared<scalar<T>>((std::forward<Args>(args))...);
}
};
template <typename T>
std::shared_ptr<scalar<T>> operator+(std::shared_ptr<scalar<T>> &lhs,
std::shared_ptr<scalar<T>> &rhs) {
auto res = scalar<T>::create(lhs->data + rhs->data, {lhs, rhs}, "+");
res->backward = [lhs, rhs, res]() {
lhs->grad += res->grad;
rhs->grad += res->grad;
};
return res;
}
and I got that error:
error: no matching function for call to ‘red_engine::scalar<double>::create(red_engine::scalar<double>::value_type, <brace-enclosed initializer list>, const char [2])’
143 | auto res = scalar<T>::create(lhs->data * rhs->data, {lhs, rhs}, "*");
| ~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/home/alex/projects/AI/nanograd/nanograd-cpp/engine.hpp:36:46: note: candidate: ‘static red_engine::scalar<T>::pointer red_engine::scalar<T>::create(Args&& ...) [with Args = {}; T = double; pointer = std::shared_ptr<red_engine::scalar<double> >]’
36 | template <typename... Args> static pointer create(Args &&...args) {
| ^~~~~~
/home/alex/projects/AI/nanograd/nanograd-cpp/engine.hpp:36:46: note: candidate expects 0 arguments, 3 provided
Can someone explain me what am I doing wrong?
Thank you in advance!
{lhs, rhs} doesn't have a type, so the respective type in Args... can't be deduced, and it seems to make the compiler assume Args is empty, hence candidate expects 0 arguments.
Use something that does have a type, like MyClass{lhs, rhs} or MyClass(lhs, rhs).

C++ constructor behave differently according to input, with help of template

I'm trying to use the template to initialize an object. The code should assign s according to different parameters input, specifically "type". However, I can't get this to work.
#include <iostream>
#include <cmath>
using namespace std;
// different discount
class Strategy {
public:
virtual double GetResult(double) = 0;
};
class SellNormal: public Strategy {
public:
double GetResult(double original) override {
return original;
}
};
class SellDiscount: public Strategy {
double rate;
public:
SellDiscount(double r){
rate = r;
}
double GetResult(double original) override {
return original * rate;
}
};
class SellReturn: public Strategy {
int fulfill;
int reduce;
public:
SellReturn(int f, int r): fulfill(f), reduce(r){}
double GetResult(double original) override {
return original - (int(original) / fulfill) * reduce;
}
};
class SellContext{
Strategy* s;
public:
enum type{
NORMAL,
DISCOUNT,
RETURN
};
template<typename ...Ts>
SellContext(type t, Ts... args){
switch(t){
case NORMAL:
s = new SellNormal();
break;
case DISCOUNT:
// double
s = new SellDiscount(args...);
break;
case RETURN:
// int, int
s = new SellReturn(args...);
break;
}
}
double getResult(double original){
return s->GetResult(original);
}
};
int main(){
auto c1 = new SellContext(SellContext::type::NORMAL);
auto c2 = new SellContext(SellContext::type::DISCOUNT, 0.8);
auto c3 = new SellContext(SellContext::type::RETURN, 300, 100);
cout << c1->getResult(1000);
cout << c2->getResult(1000);
cout << c3->getResult(1000);
}
It's telling me that C++ can't find the appropriate constructor. How should I deal with this elegantly? I know I could achieve this by overloading constructors with different parameters. But isn't that too verbose?
The errors are as below
s
trategy_pattern_with_simple_factory.cpp: In instantiation of 'SellContext::SellContext(SellContext::type, Ts ...) [with Ts = {}]':
strategy_pattern_with_simple_factory.cpp:71:56: required from here
strategy_pattern_with_simple_factory.cpp:57:17: error: no matching function for call to 'SellDiscount::SellDiscount()'
s = new SellDiscount(args...);
^~~~~~~~~~~~~~~~~~~~~~~~~
strategy_pattern_with_simple_factory.cpp:23:5: note: candidate: 'SellDiscount::SellDiscount(double)'
SellDiscount(double r){
^~~~~~~~~~~~
strategy_pattern_with_simple_factory.cpp:23:5: note: candidate expects 1 argument, 0 provided
strategy_pattern_with_simple_factory.cpp:20:7: note: candidate: 'constexpr SellDiscount::SellDiscount(const SellDiscount&)'
class SellDiscount: public Strategy {
^~~~~~~~~~~~
strategy_pattern_with_simple_factory.cpp:20:7: note: candidate expects 1 argument, 0 provided
strategy_pattern_with_simple_factory.cpp:20:7: note: candidate: 'constexpr SellDiscount::SellDiscount(SellDiscount&&)'
strategy_pattern_with_simple_factory.cpp:20:7: note: candidate expects 1 argument, 0 provided
strategy_pattern_with_simple_factory.cpp:61:17: error: no matching function for call to 'SellReturn::SellReturn()'
s = new SellReturn(args...);
^~~~~~~~~~~~~~~~~~~~~~~
strategy_pattern_with_simple_factory.cpp:35:5: note: candidate: 'SellReturn::SellReturn(int, int)'
SellReturn(int f, int r): fulfill(f), reduce(r){}
^~~~~~~~~~
strategy_pattern_with_simple_factory.cpp:35:5: note: candidate expects 2 arguments, 0 provided
strategy_pattern_with_simple_factory.cpp:31:7: note: candidate: 'constexpr SellReturn::SellReturn(const SellReturn&)'
class SellReturn: public Strategy {
^~~~~~~~~~
strategy_pattern_with_simple_factory.cpp:31:7: note: candidate expects 1 argument, 0 provided
strategy_pattern_with_simple_factory.cpp:31:7: note: candidate: 'constexpr SellReturn::SellReturn(SellReturn&&)'
strategy_pattern_with_simple_factory.cpp:31:7: note: candidate expects 1 argument, 0 provided
strategy_pattern_with_simple_factory.cpp: In instantiation of 'SellContext::SellContext(SellContext::type, Ts ...) [with Ts = {double}]':
strategy_pattern_with_simple_factory.cpp:72:63: required from here
strategy_pattern_with_simple_factory.cpp:61:17: error: no matching function for call to 'SellReturn::SellReturn(double&)'
s = new SellReturn(args...);
^~~~~~~~~~~~~~~~~~~~~~~
strategy_pattern_with_simple_factory.cpp:35:5: note: candidate: 'SellReturn::SellReturn(int, int)'
SellReturn(int f, int r): fulfill(f), reduce(r){}
^~~~~~~~~~
strategy_pattern_with_simple_factory.cpp:35:5: note: candidate expects 2 arguments, 1 provided
strategy_pattern_with_simple_factory.cpp:31:7: note: candidate: 'constexpr SellReturn::SellReturn(const SellReturn&)'
class SellReturn: public Strategy {
^~~~~~~~~~
strategy_pattern_with_simple_factory.cpp:31:7: note: no known conversion for argument 1 from 'double' to 'const SellReturn&'
strategy_pattern_with_simple_factory.cpp:31:7: note: candidate: 'constexpr SellReturn::SellReturn(SellReturn&&)'
strategy_pattern_with_simple_factory.cpp:31:7: note: no known conversion for argument 1 from 'double' to 'SellReturn&&'
strategy_pattern_with_simple_factory.cpp: In instantiation of 'SellContext::SellContext(SellContext::type, Ts ...) [with Ts = {int, int}]':
strategy_pattern_with_simple_factory.cpp:73:66: required from here
strategy_pattern_with_simple_factory.cpp:57:17: error: no matching function for call to 'SellDiscount::SellDiscount(int&, int&)'
s = new SellDiscount(args...);
^~~~~~~~~~~~~~~~~~~~~~~~~
strategy_pattern_with_simple_factory.cpp:23:5: note: candidate: 'SellDiscount::SellDiscount(double)'
SellDiscount(double r){
^~~~~~~~~~~~
strategy_pattern_with_simple_factory.cpp:23:5: note: candidate expects 1 argument, 2 provided
strategy_pattern_with_simple_factory.cpp:20:7: note: candidate: 'constexpr SellDiscount::SellDiscount(const SellDiscount&)'
class SellDiscount: public Strategy {
^~~~~~~~~~~~
strategy_pattern_with_simple_factory.cpp:20:7: note: candidate expects 1 argument, 2 provided
strategy_pattern_with_simple_factory.cpp:20:7: note: candidate: 'constexpr SellDiscount::SellDiscount(SellDiscount&&)'
strategy_pattern_with_simple_factory.cpp:20:7: note: candidate expects 1 argument, 2 provided
First, Strategy must have a virtual destructor since you'll be destroying instances via base class pointers.
It looks like you are trying to use type as some sort of tag and you can't explicitly supply template parameters to the constructor. That would be a template parameter to the class itself - and SellContext is not a class template, so using tags is a good idea. They do need to be of different types though, so I suggest creating separate tag types and also to make the pointer into a smart pointer.
Example:
#include <memory>
class SellContext{
std::unique_ptr<Strategy> s; // <- smart pointer
public:
// tag types and tag instances:
static constexpr struct NORMAL {} normal_tag{};
static constexpr struct DISCOUNT {} discount_tag{};
static constexpr struct RETURN {} return_tag{};
// The constructors you need. No `switch` needed:
template<class... Args>
SellContext(NORMAL, Args&&... args) :
s(std::make_unique<SellNormal>(std::forward<Args>(args)...)) {}
template<class... Args>
SellContext(DISCOUNT, Args&&... args) :
s(std::make_unique<SellDiscount>(std::forward<Args>(args)...)) {}
template<class... Args>
SellContext(RETURN, Args&&... args) :
s(std::make_unique<SellReturn>(std::forward<Args>(args)...)) {}
double getResult(double original){
return s->GetResult(original);
}
};
Using them would then be done like this:
int main(){
auto c1 = std::make_unique<SellContext>(SellContext::normal_tag);
auto c2 = std::make_unique<SellContext>(SellContext::discount_tag, 0.8);
auto c3 = std::make_unique<SellContext>(SellContext::return_tag, 300, 100);
std::cout << c1->getResult(1000) << '\n';
}
Demo
Using constexpr-if:
#include <type_traits>
class SellContext{
std::unique_ptr<Strategy> s;
public:
static constexpr struct NORMAL {} normal_tag{};
static constexpr struct DISCOUNT {} discount_tag{};
static constexpr struct RETURN {} return_tag{};
template<class Tag, class... Args>
SellContext(Tag, Args&&... args) {
static_assert(std::is_same_v<NORMAL, Tag> ||
std::is_same_v<DISCOUNT, Tag> ||
std::is_same_v<RETURN, Tag>);
if constexpr(std::is_same_v<NORMAL, Tag>)
s = std::make_unique<SellNormal>(std::forward<Args>(args)...);
if constexpr(std::is_same_v<DISCOUNT, Tag>)
s = std::make_unique<SellDiscount>(std::forward<Args>(args)...);
if constexpr(std::is_same_v<RETURN, Tag>)
s = std::make_unique<SellReturn>(std::forward<Args>(args)...);
}
double getResult(double original){
return s->GetResult(original);
}
};
Demo
Since the current constructors of the Strategy objects are all different, you could make it even simpler and remove the tags:
class SellContext{
std::unique_ptr<Strategy> s;
public:
SellContext() : s(std::make_unique<SellNormal>()) {}
SellContext(double x) : s(std::make_unique<SellDiscount>(x)) {}
SellContext(double x, double y) : s(std::make_unique<SellReturn>(x, y)) {}
double getResult(double original){
return s->GetResult(original);
}
};
int main(){
auto c1 = std::make_unique<SellContext>();
auto c2 = std::make_unique<SellContext>(0.8);
auto c3 = std::make_unique<SellContext>(300, 100);
std::cout << c1->getResult(1000) << '\n';
}
Demo

How to define a contructor for <...auto...>

With the following program, which is an extract from something larger that I'm experimenting with, I get an error message that seems to be related to the constructor for fixed_string
#include <string>
#include <cstring>
template<std::size_t N>
struct fixed_string {
static const constexpr std::size_t size__ = N;
constexpr fixed_string(char const* s) :
buf("") {
for (std::size_t i = 0; i <= N; ++i)
buf[i] = s[i];
}
constexpr operator char const*() const {
return buf;
}
constexpr bool operator==(const char* other) const {
return ::strncmp(buf, other, N) == 0;
}
template<std::size_t M>
constexpr bool compare(const fixed_string<M>& other) const {
return (N == M && ::strncmp(buf, other.buf, N) == 0) ? std::true_type(): std::false_type();
}
char buf[N + 1];
};
template<std::size_t N>
fixed_string(char const (&)[N]) -> fixed_string<N - 1>;
////////////////////////////////////////////
template<fixed_string TARGET_NAME, fixed_string THIS_NAME>
concept NameMatches = (TARGET_NAME.compare(THIS_NAME));
template<fixed_string NAME, typename TYPE>
class Member {
public:
static const constexpr fixed_string name__ { NAME };
public:
template<fixed_string TARGET_NAME>
const TYPE& get() const requires NameMatches<TARGET_NAME, TYPE::name__> const {
return member_;
}
protected:
TYPE member_;
};
template<typename ... MEMBERS>
class Container: public MEMBERS... {
};
The error messages are:
../src/test-concepts.cpp:43:35: error: class template argument deduction failed:
43 | const TYPE& get() const requires NameMatches<TARGET_NAME, TYPE::name__> const {
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
../src/test-concepts.cpp:43:35: error: no matching function for call to ‘fixed_string(fixed_string<...auto...>)’
../src/test-concepts.cpp:8:12: note: candidate: ‘template<long unsigned int N> fixed_string(const char*)-> fixed_string<N>’
8 | constexpr fixed_string(char const* s) :
| ^~~~~~~~~~~~
../src/test-concepts.cpp:8:12: note: template argument deduction/substitution failed:
../src/test-concepts.cpp:43:35: note: couldn’t deduce template parameter ‘N’
43 | const TYPE& get() const requires NameMatches<TARGET_NAME, TYPE::name__> const {
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
../src/test-concepts.cpp:5:8: note: candidate: ‘template<long unsigned int N> fixed_string(fixed_string<N>)-> fixed_string<N>’
5 | struct fixed_string {
| ^~~~~~~~~~~~
../src/test-concepts.cpp:5:8: note: template argument deduction/substitution failed:
../src/test-concepts.cpp:43:35: note: mismatched types ‘fixed_string<N>’ and ‘fixed_string<...auto...>’
43 | const TYPE& get() const requires NameMatches<TARGET_NAME, TYPE::name__> const {
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
../src/test-concepts.cpp:28:1: note: candidate: ‘template<long unsigned int N> fixed_string(const char (&)[N])-> fixed_string<(N - 1)>’
28 | fixed_string(char const (&)[N]) -> fixed_string<N - 1>;
| ^~~~~~~~~~~~
../src/test-concepts.cpp:28:1: note: template argument deduction/substitution failed:
../src/test-concepts.cpp:43:35: note: mismatched types ‘const char [N]’ and ‘fixed_string<...auto...>’
43 | const TYPE& get() const requires NameMatches<TARGET_NAME, TYPE::name__> const {
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
../src/test-concepts.cpp:43: confused by earlier errors, bailing out
This is part of a project using templates that overloads a given function (get in this case), for which there is only one suitable candidate that fulfils the constraint. The value that the constraint operates on is a name - a string literal - not a const string variable, which is passed as a non-type parameter to an instantiation of the template: something like:
Container<Member<"fred", std::string>, Member<"bert", int>, Member<"alfie", bool>> some_values;
I want to be able to retrieve a value using something like
int result = some_values.get<"bert">();
I have had difficulty finding much information about the "<...auto...>" specialisation of the template. I presume this is an internal representation used by gcc for constant, non-type values.
The error messages point me to the lack of a suitable overloaded constructor for fixed_string. What should this be?
The problem I see is that fixed_string is a template class, not a class.
So, when you define a concept as
template<fixed_string TARGET_NAME, fixed_string THIS_NAME>
concept NameMatches = (TARGET_NAME.compare(THIS_NAME));
you have that fixed_string TARGET_NAME (fixed_string THIS_NAME also) doesn't works because fixed_string isn't a type. I mean: fixed_string<5> is a type, not fixed_string.
I know that you have a deduction guide that, given the literal string, deduce the template parameter for the fixed_string, but remain the problem that the concept should works with elements of different types (fixed_string of different lengths).
I suppose you can solve the problem with auto
template <auto TARGET_NAME, auto THIS_NAME>
concept NameMatches = (TARGET_NAME.compare(THIS_NAME));
but, when you declare Member, you have the same problem: fixed_string NAME doesn't works because fixed_sting (without a length) isn't a type.
template<fixed_string NAME, typename TYPE>
class Member
Unfortunately, if you use auto
template <auto NAME, typename TYPE>
class Member
defining a Member with a literal string argument (Member<"bert", int>, by example), nothing bring "bert" to a fixed_string.
Suggestion: what about a fixed_string without a template argument?

c++ type traits : ensuring a subclass implements a method

There is a virtual class C.
I would like to ensure that any concrete subclass inheriting from C implements a function "get" (and have a clear compile time error if one does not)
Adding a virtual "get" function to C would not work in this case, as C subclasses could implement get functions of various signatures.
(in the particular case I am working on, pybind11 will be used to creates bindings of the subclasses, and pybind11 is robust of the "get" method of B to have a wide range of signatures)
Checking at compile time if a class has a function can be done with type traits, e.g.
template<class T>
using has_get =
decltype(std::declval<T&>().get(std::declval<int>()));
My question is where in the code should I add a static assert (or smthg else) to check the existence of the "get" function. Ideally, this should be part of C declaration, as things should be easy for new user code inheriting from it. It may also be that a completely different approach would be better, which I'd like to hear.
Not sure what standard you are using but with C++20 you can do something like this using concepts
template<typename T>
concept HasGet = requires (T a)
{
a.get();
};
template<HasGet T>
void foo(T x)
{
x.get();
}
struct Foo
{
int get() {
return 1;
}
};
struct Bar
{
};
int main()
{
foo(Foo{});
foo(Bar{});
}
Error:
<source>: In function 'int main()':
<source>:27:12: error: use of function 'void foo(T) [with T = Bar]' with unsatisfied constraints
27 | foo(Bar{});
| ^
<source>:8:6: note: declared here
8 | void foo(T x)
| ^~~
<source>:8:6: note: constraints not satisfied
<source>: In instantiation of 'void foo(T) [with T = Bar]':
<source>:27:12: required from here
<source>:2:9: required for the satisfaction of 'HasGet<T>' [with T = Bar]
<source>:2:18: in requirements with 'T a' [with T = Bar]
<source>:4:9: note: the required expression 'a.get()' is invalid
4 | a.get();
EDIT:
As C++14 is preferred, if I understand you requirements, this is something you can do in C++14
#include <type_traits>
#include <utility>
using namespace std;
template<typename... Ts>
using void_t = void;
template<typename T, typename = void>
struct has_get
: false_type
{};
template<typename T>
struct has_get<T, void_t<decltype(declval<T>().get())>>
: true_type
{};
template<typename T>
static constexpr auto has_get_v = has_get<T>::value;
struct P
{
};
struct C1 : P
{
int get()
{
return 1;
}
};
struct C2 : P
{
float get()
{
return 1.0F;
}
};
struct C3
{
bool get()
{
return true;
}
};
template<typename T>
enable_if_t<is_base_of<P, decay_t<T>>::value && has_get_v<decay_t<T>>> foo(T x)
{
x.get();
}
int main()
{
foo(C1{});
foo(C2{});
foo(C3{});
}
ERROR:
<source>: In function 'int main()':
<source>:61:11: error: no matching function for call to 'foo(C3)'
61 | foo(C3{});
| ^
<source>:52:77: note: candidate: 'template<class T> std::enable_if_t<(std::is_base_of<P, typename std::decay<_Tp>::type>::value && has_get<typename std::decay<_Tp>::type>::value)> foo(T)'
52 | enable_if_t<is_base_of<P, decay_t<T>>::value && has_get<decay_t<T>>::value> foo(T x)
| ^~~
<source>:52:77: note: template argument deduction/substitution failed:
In file included from <source>:1:
/opt/compiler-explorer/gcc-10.1.0/include/c++/10.1.0/type_traits: In substitution of 'template<bool _Cond, class _Tp> using enable_if_t = typename std::enable_if::type [with bool _Cond = false; _Tp = void]':
<source>:52:77: required by substitution of 'template<class T> std::enable_if_t<(std::is_base_of<P, typename std::decay<_Tp>::type>::value && has_get<typename std::decay<_Tp>::type>::value)> foo(T) [with T = C3]'
<source>:61:11: required from here
/opt/compiler-explorer/gcc-10.1.0/include/c++/10.1.0/type_traits:2554:11: error: no type named 'type' in 'struct std::enable_if<false, void>'
2554 | using enable_if_t = typename enable_if<_Cond, _Tp>::type;

Pass a templatized type to a member function in C++

I'm trying to write a member function that can instantiate an object of a custom type (templatized), initializing its const& member to a local object of the function.
This is consistent since the lifetime of the custom type object is the same as the local_object.
The objective is caching some metadata of the local object because they don't change during its lifetime. The operator() (or any member function) computes some values, then used later in func, and the objective is offering a hook to change the behaviour of func.
Please no polymorphic solutions (currently used) due to (profiled) slowness.
This is a M(N)WE:
#include <vector>
class cls {
public:
template <typename Custom> int func() {
std::vector<int> local_object{0, 14, 32};
Custom c(local_object, 42);
return c();
}
};
template<typename AType> class One {
public:
One(const AType& obj, const int n): objref(obj), param(n), member_that_should_depend_on_objref(obj.size()) {}
int operator()() { return 42; }
private:
const AType& objref;
const int param;
float member_that_should_depend_on_objref;
};
template<typename AType> class Two {
public:
Two(const AType& obj, const int n): objref(obj), param(n), other_member_that_should_depend_on_objref(obj.empty()), other_dependent_member(obj.back()) {}
int operator()() { return 24; }
private:
const AType& objref;
const int param;
bool other_member_that_should_depend_on_objref;
int other_dependent_member;
};
int main() {
cls myobj;
auto a = myobj.func<One>();
auto b = (myobj.func<Two>)();
}
G++ 5.3.0 says
tmp.cpp: In function 'int main()':
tmp.cpp:34:30: error: no matching function for call to 'cls::func()'
auto a = myobj.func<One>();
^
tmp.cpp:4:36: note: candidate: template<class Custom> int cls::func()
template <typename Custom> int func() {
^
tmp.cpp:4:36: note: template argument deduction/substitution failed:
tmp.cpp:35:32: error: no matching function for call to 'cls::func()'
auto b = (myobj.func<Two>)();
^
tmp.cpp:4:36: note: candidate: template<class Custom> int cls::func()
template <typename Custom> int func() {
^
tmp.cpp:4:36: note: template argument deduction/substitution failed:
Clang++ 3.7.1 says:
tmp.cpp:34:20: error: no matching member function for call to 'func'
auto a = myobj.func<One>();
~~~~~~^~~~~~~~~
tmp.cpp:4:36: note: candidate template ignored: invalid explicitly-specified argument for template
parameter 'Custom'
template <typename Custom> int func() {
^
tmp.cpp:35:21: error: no matching member function for call to 'func'
auto b = (myobj.func<Two>)();
~~~~~~~^~~~~~~~~~
tmp.cpp:4:36: note: candidate template ignored: invalid explicitly-specified argument for template
parameter 'Custom'
template <typename Custom> int func() {
^
2 errors generated.
auto a = myobj.func<One>();
is wrong since One is a class template, not a class. Use
auto a = myobj.func<One<SomeType>>();
It's not clear from your code what SomeType should be.
Update
If you want to use:
auto a = myobj.func<One>();
you need to change func to use a template template parameter:
class cls {
public:
template <template <class> class Custom > int func() {
std::vector<int> local_object{0, 14, 32};
Custom<std::vector<int>> c(local_object, 42);
return c();
}
};
Perhaps that was your intention.