dllexport类模板实例(专业化,减少了仅标头模板库的编译时间)

问题描述 投票:0回答:1

可以导出某些类模板实例,同时让库的用户能够生成给定类模板的其他特殊化功能(在编译可执行文件时。)>

鉴于我有一个公共标题

// 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>;

可以导出某些类模板实例,同时让图书馆的用户能够生成给定类模板的其他特化功能(编译时...

c++ dll class-template template-instantiation
1个回答
0
投票

这是导出类模板实例的简单方法。

© www.soinside.com 2019 - 2024. All rights reserved.