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

时间:2014-10-10 15:46:36

标签: c++ c++11 generic-programming cppunit

popular library的作者决定实施the following design pattern

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

现在假设该库使用如下:

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

int main() {
        my_test1();
        my_test2();
        return 0;
}

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

void my_test1() {
        my_assert(-1.0, -1.0);
}

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

现在,

$ g++ main.cpp my_test1.cpp my_test2.cpp && ./a.out
base
base

,而

$ g++ main.cpp my_test2.cpp my_test1.cpp && ./a.out
specialization
specialization

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

base
specialization

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

1 个答案:

答案 0 :(得分:5)

§14.7.3[temp.expl.spec] / p6(强调补充):

  

如果是模板,成员模板或类模板的成员   明确专门然后应宣布专业化   在第一次使用该特化之前会导致一个   隐式实例化发生在每个翻译单元中   发生了这种用途;无需诊断。如果是程序   没有为显式专业化提供定义   专业化的使用方式会导致   隐式实例化发生或成员是虚拟成员   功能,程序格式错误,无需诊断。