[英]Calling different constructor signatures of templated Types
我手頭有大量的模板代碼,其中應該用作用戶代碼模板參數的類具有不同的構造函數簽名。 我的問題是,我還沒有找到在用戶代碼中調用模板化類的構造函數的好方法。 一個最小的工作示例可能如下所示:
#include <string>
#include <iostream>
#include <memory>
class ShortConstructorInLibrary {
std::string myName;
static const int tag = 1;
public:
ShortConstructorInLibrary(std::string name) :
myName(name) {
}
};
class LongConstructorInLibrary {
private:
int a;
double b;
public:
static const int tag = 2;
LongConstructorInLibrary(int arg1, double arg2) :
a(arg1), b(arg2) {
}
};
//above is library code
template<typename T>
class MyClass {
std::shared_ptr<T> member_p;
//i want to call right constructor for both cases:
public:
MyClass() {
//how do i call the different constructors properly?!
member_p = std::shared_ptr<T>(new T("test"));
}
};
int main() {
MyClass<ShortConstructorInLibrary> obj; //works
//MyClass<LongConstructorInLibrary> obj2; // wrong constructor signature
}
在這里,我在一個庫中有兩個類,一個類具有較長且無關的構造函數簽名,一個類具有較短的類。 我希望能夠將它們都用作模板參數。 在我的userClass中,我必須以某種方式定義要傳遞給構造函數的參數,具體取決於傳遞的類型。
我不能使用簡單的if(),因為編譯器將同時檢查兩個簽名,而一個簽名將是錯誤的。 我不能將c ++ 17用作“ if constexpr(){}”。
我可以將模板參數“ ShortConstructorInLibrary”傳遞給我的類,並完美地調用它的構造函數,但是當我使用另一個類時,它當然會因錯誤的構造函數簽名而失敗。 到目前為止,我使用了一個丑陋的把戲,以至於我實現了兩個輔助方法,在該方法中我傳遞了一個指針,然后讓這兩個方法實現了構造函數調用,但這對我來說似乎很丑陋。 我還擺弄了std :: enable_if <>,但走得並不遠。 @Mohit提議使用部分模板專門化,但是在現實世界的代碼中,Short ConstructorInLibrary類本身是使用兩個... templateed模板參數進行模板化的。 給您一個想法:
‘class CFEM_LOP<Dune::PDELab::QkLocalFiniteElementMap<Dune::GridView<Dune::DefaultLeafGridViewTraits<const Dune::YaspGrid<2> > >, double, double, 1ul>, EngwHillenKnapp2014<MedicalDataManager<double, Dune::YaspGrid<2> >, Dune::YaspGrid<2> >, CFEM_L2OP<Dune::PDELab::QkLocalFiniteElementMap<Dune::GridView<Dune::DefaultLeafGridViewTraits<const Dune::YaspGrid<2> > >, double, double, 1ul> >, Dune::YaspGrid<2> >’
我跌倒了,試圖專門化我的用戶代碼將是一團糟。
實施可能變化的簽名的構造函數調用的正確方法是什么?
任何提示將不勝感激!
(Ubuntu 16.04,GCC)
嘗試使用部分專業化方法來實現這一點,我使用std::make_shared
創建std::shared_ptr
class ShortConstructorInLibrary
{
std::string myName;
static const int tag = 1;
public:
ShortConstructorInLibrary(std::string name) :
myName(name)
{
}
};
class LongConstructorInLibrary
{
private:
int a;
double b;
public:
static const int tag = 2;
LongConstructorInLibrary(int arg1, double arg2) :
a(arg1), b(arg2)
{
}
};
//above is library code
template<typename T>
class MyClass
{
std::shared_ptr<T> member_p;
//i want to call right constructor for both cases:
public:
MyClass()
{
//how do i call the different constructors properly?!
member_p = std::make_shared<T>("test");
}
};
template<>
MyClass<LongConstructorInLibrary>::MyClass()
{
member_p = std::make_shared<LongConstructorInLibrary>(0, 0.0); // pass you values.
}
int main()
{
MyClass<LongConstructorInLibrary> obj; //works
//MyClass<LongConstructorInLibrary> obj2; // wrong constructor signature
}
MyClass
的構造函數應該創建一個T
類型的對象。 假定作為模板參數傳遞的每個T
具有不同的構造函數簽名,因此您需要將構造T
所需的參數傳遞給類MyClass
並轉發這些參數。 這是可能的,因為c ++ 11具有可變參數模板,即
template <class T>
struct MyClass
{
std::shared_ptr<T> member_p;
template <class... Args>
MyClass(Args&&... args)
: member_p(std::make_shared<T>(std::forward<Args>(args)...))
{}
};
int main() {
MyClass<ShortConstructorInLibrary> obj1("test");
MyClass<LongConstructorInLibrary> obj2(1, 2.0);
}
您只需要謹慎使用可變的通用構造函數參數,因為這也涵蓋了復制/移動構造函數。 為了不使用您的書面構造函數停用這些功能,您必須添加一點enable_if
代碼。 由於使用Dune
,因此您可以簡單地應用一個通用模式:
template <class... Args, Dune::disableCopyMove<MyClass, Args...> = 0>
MyClass(Args&&... args)
: member_p(std::make_shared<T>(std::forward<Args>(args)...))
{}
disableCopyMove
是enable_if
的包裝,如果將MyClass const&
或MyClass&&
傳遞給構造函數,則會導致替換失敗,從而使自定義構造函數不會隱藏copy和move構造函數。 = 0
是必需的,因為此enable_if
包裝器定義的類型是int
,而= 0
是此非類型模板參數的默認值,因此您無需自己指定它。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.