可以导出某些类模板实例,同时让库的用户能够生成给定类模板的其他特殊化功能(在编译可执行文件时。)>
鉴于我有一个公共标题
// public.h #pragma once #ifndef DLL_BUILD #define API __declspec(dllimport) #else #define API __declspec(dllexport) #endif // !DLL_BUILD #include <type_traits> // dummy to generate .lib struct API dummy { void be_dummy(); }; template <class T> struct Foo { static T Sum(T a, T b) { static_assert(std::is_fundamental_v<T>); return a + b; } };
使用这种声明类模板
Foo
的方式,每个实例化都将在用户的可执行文件中进行。
但是,如果我使用Foo
宏将dllexport/dllimport
定义为API
,则未在dll内部明确实例化的Foo
的每个特殊化都将无法链接。
// impl.cpp - dll #include "public.h" void dummy::be_dummy() { volatile int a = 0; return; } template API struct Foo<int>; /////////////////////////////////////////// // main.cpp - executable #include "public.h" #include <iostream> int main() { dummy().be_dummy(); // std::cout << Foo<double>().Sum(4.12, 3.18) << std::endl; // Unresolved external symbol std::cout << Foo<int>().Sum(60, 9) << std::endl; // executed within the dll return 0; }
因此,当一个已导出的类模板实例被强制导出时,它可以强制编译器链接到现有的类模板实例,而生成一个还没有的实例模板实例。
UPDATE
我找到了解决方案,请参阅下面的答案。我保留旧的更新,以防万一有人发现SFINAE的这种用法会有所帮助。
UPDATE OLD
我发现了一个涉及SFINAE的繁琐解决方案,但是它导致两次定义类模板,因此非常容易出错。我不知道是否可以用宏将其包裹起来,从而只能编写一次。
// public.h
#pragma once
#ifndef DLL_BUILD
#define API __declspec(dllimport)
#else
#define API __declspec(dllexport)
#endif // !DLL_BUILD
#include <type_traits>
namespace templ_export
{
template <class T>
struct is_exported : std::false_type {};
// this can be placed to a separated header (i.e. Exported.hpp)
template <> struct is_exported<int> : std::true_type {};
template <class T>
struct API FooExported
{
static T Sum(T a, T b)
{
//static_assert(std::is_fundamental_v<T>);
return a + b;
}
};
template <class T>
struct FooNotExported
{
static T Sum(T a, T b)
{
//static_assert(std::is_fundamental_v<T>);
return a + b;
}
};
template <class T, bool = templ_export::is_exported<T>()>
struct GetFooExported
{
using type = FooNotExported<T>;
};
template <class T>
struct GetFooExported<T, true>
{
using type = FooExported<T>;
};
}
template <class T>
using Foo = typename templ_export::GetFooExported<T>::type;
/////////////////////////////////
// impl.cpp
#include "public.h"
void dummy::be_dummy()
{
volatile int a = 0;
return;
}
template struct API templ_export::FooExported<int>;
可以导出某些类模板实例,同时让图书馆的用户能够生成给定类模板的其他特化功能(编译时...
这是导出类模板实例的简单方法。