一个定义规则和模板类特化

vla*_*adr 3 c++ cppunit generic-programming c++11

一个受欢迎的图书馆的作者决定实施以下设计模式:

// my_traits.hpp
#include <stdio.h>
#include <assert.h>

template<typename T>
struct my_traits {
        static bool equals(const T& x, const T& y) {
                printf("base\n");
                return x == y;
        }
};

template<typename T>
void my_assert(const T& x, const T& y) {
        assert(my_traits<T>::equals(x, y));
}
Run Code Online (Sandbox Code Playgroud)

现在假设库使用如下:

// main.cpp
void my_test1();
void my_test2();

int main() {
        my_test1();
        my_test2();
        return 0;
}
Run Code Online (Sandbox Code Playgroud)

// my_test1.cpp
#include "my_traits.hpp"

void my_test1() {
        my_assert(-1.0, -1.0);
}
Run Code Online (Sandbox Code Playgroud)

//my_test2.cpp
#include "my_traits.hpp"

#ifdef _WIN32
#include <float.h>
#define isnan _isnan
#else
#include <math.h>
#endif

template<>
struct my_traits<double> {
        static bool equals(const double& x, const double& y) {
                printf("specialization\n");
                return x == y || isnan(x) && isnan(y);
        }
};

void my_test2() {
        my_assert(-1.0, -1.0);
}
Run Code Online (Sandbox Code Playgroud)

现在,

$ g++ main.cpp my_test1.cpp my_test2.cpp && ./a.out
base
base
Run Code Online (Sandbox Code Playgroud)

$ g++ main.cpp my_test2.cpp my_test1.cpp && ./a.out
specialization
specialization
Run Code Online (Sandbox Code Playgroud)

当然,无论链接顺序如何,库的用户都希望获得以下结果:

base
specialization
Run Code Online (Sandbox Code Playgroud)

没有专门化或超载(内联)my_assert而不my_traits知道并且知道将相同的专业化注入到my_traits.hpp包含的每个翻译单元是不可接受的(或可维护的),任何人都可以想到另一种技巧,在不修改my_traits.hpp或专门化的情况下实现所需的行为my_assert(或使用kludgy包装类double:))?

T.C*_*.C. 6

§14.7.3[temp.expl.spec]/p6(重点补充):

如果模板,成员模板或类模板的成员是显式专用的,则应在首次使用该特化之前声明该特化,这将导致发生隐式实例化,在发生此类使用的每个翻译单元中 ; 无需诊断.如果程序没有提供显式特化的定义,并且特殊化的使用方式会导致隐式实例化或成员是虚拟成员函数,则程序格式错误,无需诊断.