如何在type<T>不完整时调用模板函数func<T>且仅编写一次函数体
问题:模板函数跨上下文调用的实现需求
我需要设计模板函数func<T>,要求所有T对应的函数体完全一致,仅编写一次即可复用。但该函数的正常运行依赖type<T>的定义,而部分上下文环境中不存在type<T>的定义。以下是C++17环境下的示例代码:
type.h
#include <stddef.h> #include <stdint.h> #include <type_traits> template<typename T, typename = void> struct type; template<typename T> inline size_t func() { return type<T>::magic; } template<typename T> struct type<T, std::enable_if_t<std::is_arithmetic_v<T>>> { static constexpr size_t magic = sizeof(T) * 2; };
my_type.h
struct MyStruct { int a; static void Dummy(); };
my_type.cpp
#include "my_type.h" #include "type.h" template<> struct type<MyStruct> { static constexpr size_t magic = 123; }; void MyStruct::Dummy() { (void)func<MyStruct>(); }
main.cpp
#include "my_type.h" #include "type.h" int main(int argc, char **argv) { func<int>(); // OK func<MyStruct>(); // Error }
核心需求
- 仅编写一次
func<T>的函数体。 - 在
type<T>未完整定义的上下文环境中也能调用func<T>。
说明:
Dummy函数用于强制编译器生成func<MyStruct>的代码,确保链接器正常工作。
补充细节
问:为何不将特化定义放在main可引用的头文件中?
答:头文件type.h属于某库文件,其余代码为用户代码。部分类型T的type<T>特化定义在工具生成的源文件中,无法随库发布。
问:调用func<T>但无type定义时,期望什么结果?除编译错误外无法理解其他可能性。
答:库中已包含func<MyStruct>的实现,希望编译器仅在main.o中保留符号引用,而非尝试生成函数实现导致错误。
可行解决方案
以下方案可在本地正常运行,满足需求:
修改后的type.h
#include <stddef.h> #include <stdint.h> #include <type_traits> template <typename T, typename = void> struct is_complete : std::false_type {}; template <typename T> struct is_complete<T, decltype(void(sizeof(T)))> : std::true_type {}; template <typename T> inline constexpr auto is_complete_v = is_complete<T>::value; template<typename T, typename = void> struct type; template <typename T, std::enable_if_t<is_complete_v<type<T>>>* = nullptr> inline size_t func() { return type<T>::magic; } template <typename T, std::enable_if_t<!is_complete_v<type<T>>>* = nullptr> size_t func(); template<typename T> struct type<T, std::enable_if_t<std::is_arithmetic_v<T>>> { static constexpr size_t magic = sizeof(T) * 2; };
该方案中,func<T>的函数体仍只需编写一次,且无论type<T>是否已定义,用户均可调用func<T>。同时仍需保留类似MyStruct::Dummy的逻辑——至少需要在type<T>已定义的上下文环境中显式调用一次func<T>,才能促使编译器生成func<MyStruct>的代码。
内容的提问来源于stack exchange,提问作者王雨泽
相关产品推荐
相关产品推荐

