在模板的帮助下,C++ 构造函数根据输入表现不同
C++ constructor behave differently according to input, with help of template
我正在尝试使用模板来初始化一个对象。代码应根据不同的参数输入分配 s,特别是“类型”。但是,我无法让它工作。
#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);
}
它告诉我 C++ 找不到合适的构造函数。我应该如何优雅地处理这个问题?我知道我可以通过使用不同参数重载构造函数来实现这一点。但是这样是不是太冗长了?
报错如下
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
首先,Strategy
必须有一个 virtual
析构函数,因为您将通过基础 class 指针销毁实例。
看起来您正在尝试将 type
用作某种标记,并且您不能显式地向构造函数提供模板参数。那将是 class 本身的模板参数 - 而 SellContext
不是 class 模板,因此使用标签是个好主意。不过它们确实需要不同的类型,所以我建议创建单独的标记类型,并将指针变成智能指针。
示例:
#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);
}
};
然后像这样使用它们:
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';
}
使用 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);
}
};
由于 Strategy
对象的当前构造函数都不相同,您可以更简单地删除标签:
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';
}
我正在尝试使用模板来初始化一个对象。代码应根据不同的参数输入分配 s,特别是“类型”。但是,我无法让它工作。
#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);
}
它告诉我 C++ 找不到合适的构造函数。我应该如何优雅地处理这个问题?我知道我可以通过使用不同参数重载构造函数来实现这一点。但是这样是不是太冗长了?
报错如下
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
首先,Strategy
必须有一个 virtual
析构函数,因为您将通过基础 class 指针销毁实例。
看起来您正在尝试将 type
用作某种标记,并且您不能显式地向构造函数提供模板参数。那将是 class 本身的模板参数 - 而 SellContext
不是 class 模板,因此使用标签是个好主意。不过它们确实需要不同的类型,所以我建议创建单独的标记类型,并将指针变成智能指针。
示例:
#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);
}
};
然后像这样使用它们:
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';
}
使用 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);
}
};
由于 Strategy
对象的当前构造函数都不相同,您可以更简单地删除标签:
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';
}