C++ 约束API模板类型
我的类中有一个名为C++ 约束API模板类型,c++,templates,c++11,C++,Templates,C++11,我的类中有一个名为template T Get(/*stuff*/)的模板API函数。我的源文件为T类型的特定列表实现此功能。如果用户希望使用我尚未实现的类型,那么我希望结果是编译错误,而不是链接器错误。我还不太关心编译消息。以下是到目前为止我得到的信息: MyClass.h #pragma once #define API_TYPE(X) \ template<> struct Implemented<X> : public API<X> {} na
template T Get(/*stuff*/)的模板API函数代码>。我的源文件为T
类型的特定列表实现此功能。如果用户希望使用我尚未实现的类型,那么我希望结果是编译错误,而不是链接器错误。我还不太关心编译消息。以下是到目前为止我得到的信息:
MyClass.h
#pragma once
#define API_TYPE(X) \
template<> struct Implemented<X> : public API<X> {}
namespace MyClassAPI
{
template<typename T> struct API
{
static T Get(const T&);
};
template<typename T> struct Implemented {};
API_TYPE(bool);
}
class MyClass
{
template<typename T> friend struct MyClassAPI::API;
public:
template<typename T> T Get(const T& t) const
{
return MyClassAPI::Implemented<T>::Get(t);
}
};
#pragma一次
#定义API_类型(X)\
已实现模板结构:公共API{}
名称空间MyClassAPI
{
模板结构API
{
静态T得到(常数T&);
};
实现的模板结构{};
API_类型(bool);
}
类MyClass
{
模板友元结构MyClassAPI::API;
公众:
模板T获取(常量T&T)常量
{
返回MyClassAPI::Implemented::Get(t);
}
};
MyClass.cpp
#include "MyClass.h"
namespace MyClassAPI
{
template<typename T> T API<T>::Get(const T& t) { return t; }
//template struct API<bool> //Why do I need this?
}
#包括“MyClass.h”
名称空间MyClassAPI
{
模板tapi::Get(const T&T){return T;}
//模板结构API//为什么我需要这个?
}
main.cpp
#include "MyClass.h"
#include <iostream>
#include <cassert>
using namespace std;
// Main File
int main() {
MyClass c;
cout << "Getting true: " << c.Get(true) << endl;
return 0;
}
#包括“MyClass.h”
#包括
#包括
使用名称空间std;
//主文件
int main(){
MyClass c;
CUT< P>你的模板的问题是你在一个单独的翻译单元中定义它的成员,因此它们对Meal.CPP不可见,C++不支持模板的单独翻译。
当您使用template struct API;
时,您要求编译器显式地实例化T=bool
的API
。但是,在这样做时,您还应该让其他翻译单元知道实例化发生在其他地方,方法是在头文件中使用模板decla的类似指令配给:
extern template struct API<bool>;
现在,既然在
中,我们就可以使用静态断言
并明确指定模板的可行类型:
template<typename T> struct API
{
// Only allow API<bool> and API<int>
static_assert(is_in<T, bool, int>::value, "invalid template type for API<T>");
static T Get(const T&);
};
模板结构API
{
//仅允许使用API和API
静态_断言(是_in::value,“API的模板类型无效”);
静态T得到(常数T&);
};
你几乎就在那里了
您需要更新MyClass.h
以提供两个函数的显式实例化,并在MyClass.cpp
中实现它们
在.h文件中,添加:
// Explicit instantiations
namespace MyClassAPI
{
template<> int API<int>::Get(const int&);
template<> double API<double>::Get(const double&);
}
// Implement the explicit instantiations
namespace MyClassAPI
{
template<> int API<int>::Get(const int& in)
{
// Add whatever logic that makes sense for this type.
return 2*in;
}
template<> double API<double>::Get(const double& in)
{
// Add whatever logic that makes sense for this type.
return 10*in;
}
}
更新
这是一个多文件版本:
MyClass.h:
#pragma once
#define API_TYPE(X) \
template<> struct Implemented<X> : public API<X> {}
namespace MyClassAPI
{
template<typename T> struct Implemented;
template<typename T> struct API
{
static T Get(T const&);
};
API_TYPE(int);
API_TYPE(double);
}
class MyClass
{
template<typename T> friend struct MyClassAPI::API;
public:
template<typename T> T Get(const T& t) const
{
return MyClassAPI::Implemented<T>::Get(t);
}
};
// Explicit instantiations
namespace MyClassAPI
{
template<> int API<int>::Get(const int&);
template<> double API<double>::Get(const double&);
}
#pragma一次
#定义API_类型(X)\
已实现模板结构:公共API{}
名称空间MyClassAPI
{
实现了模板结构;
模板结构API
{
静态T得到(T常数&);
};
API_类型(int);
API_型(双);
}
类MyClass
{
模板友元结构MyClassAPI::API;
公众:
模板T获取(常量T&T)常量
{
返回MyClassAPI::Implemented::Get(t);
}
};
//显式实例化
名称空间MyClassAPI
{
模板INTAPI::Get(const int&);
模板双API::Get(constdouble&);
}
MyClass.cc:
#include "MyClass.h"
// Implement the explicit instantiations
namespace MyClassAPI
{
template<> int API<int>::Get(const int& in)
{
return 2*in;
}
template<> double API<double>::Get(const double& in)
{
return 10*in;
}
}
#包括“MyClass.h”
//实现显式实例化
名称空间MyClassAPI
{
模板intapi::Get(const int&in)
{
返回2*in;
}
模板双API::Get(constdouble&in)
{
返回10*in;
}
}
main.cc:
#include <iostream>
#include "MyClass.h"
int main()
{
MyClass a;
std::cout << a.Get<int>(10) << std::endl;
std::cout << a.Get<double>(10) << std::endl;
// Does not work.
// std::cout << a.Get<float>(10) << std::endl;
}
#包括
#包括“MyClass.h”
int main()
{
我的a级;
std::cout“将定义移动到头文件”在实现的定义之前,我尝试将模板结构API;
移动到头文件,但仍然出现相同的链接器错误。我建议移动模板T API::get(const T&T){return T;}“/Cord>”到头文件,而不是显式实例化。显式实例化属于C++文件,也应在头文件中显式地声明特定的<代码> T 的实例化发生在另一个文件中:外部模板模板结构API;< /Cord> HMM,而不是因为实际函数G。et相当复杂,只调用实现文件中定义的函数。顺便问一下,
方法中的is_不是也有同样的问题吗,我需要列出两次接受的类型(假设我不移动获取
的定义)如果您缺少extern-template-struct-API;
声明,请将它与模板一起添加到头文件中,让编译器和链接器知道Get
是在其他地方定义的。总之,如果您没有做template/extern-template
之类的工作,您应该为您类型的每个用户提供定义对于Get
。到目前为止,您只是声明它,而不是定义它。main.cpp
中的代码没有Get
的定义,因此链接器无法找到它。如果您想将Get
的定义保留在单独的翻译单元中,并且定义它的类型集非常窄,那么您应该有一个对于头文件和.cpp文件中的每种类型,相应地有一对extern-template
和template
声明。单文件版本不算,因为如果我的代码也都在一个文件中,它就可以工作。你必须确保将显式实例化分开,以确保它们实际上是这样做的。@Suedocode,我添加了多文件版本,结果是一样的。此外,它仍然列出了两次实现的类型,但更详细。我认为除了宏魔法之外,没有什么能满足我的要求。我想你不是想在头文件中有显式实例化
?@Suedocode,是的,我有。这告诉编译器软管功能被实例化并在其他地方实现。
20
100
#pragma once
#define API_TYPE(X) \
template<> struct Implemented<X> : public API<X> {}
namespace MyClassAPI
{
template<typename T> struct Implemented;
template<typename T> struct API
{
static T Get(T const&);
};
API_TYPE(int);
API_TYPE(double);
}
class MyClass
{
template<typename T> friend struct MyClassAPI::API;
public:
template<typename T> T Get(const T& t) const
{
return MyClassAPI::Implemented<T>::Get(t);
}
};
// Explicit instantiations
namespace MyClassAPI
{
template<> int API<int>::Get(const int&);
template<> double API<double>::Get(const double&);
}
#include "MyClass.h"
// Implement the explicit instantiations
namespace MyClassAPI
{
template<> int API<int>::Get(const int& in)
{
return 2*in;
}
template<> double API<double>::Get(const double& in)
{
return 10*in;
}
}
#include <iostream>
#include "MyClass.h"
int main()
{
MyClass a;
std::cout << a.Get<int>(10) << std::endl;
std::cout << a.Get<double>(10) << std::endl;
// Does not work.
// std::cout << a.Get<float>(10) << std::endl;
}