C++ SFINAE模板专用化在单独的源文件中

C++ SFINAE模板专用化在单独的源文件中,c++,c++11,templates,sfinae,C++,C++11,Templates,Sfinae,我正在维护一个程序,该程序具有一系列基本相似的不同结构。我想编写一个模板方法,利用SFINAE从客户端调用这个方法。当我内联定义模板专门化时,一切都按预期进行。然而,当我试图将模板定义移动到一个单独的编译单元中时,我遇到了一些问题。我试图将模板实现移动到一个单独的文件中,以便为大多数依赖类启用前向声明。以下是我试图实现的一个示例: // Impl.h #pragma once struct A { struct { int value; } valueA; };

我正在维护一个程序,该程序具有一系列基本相似的不同结构。我想编写一个模板方法,利用SFINAE从客户端调用这个方法。当我内联定义模板专门化时,一切都按预期进行。然而,当我试图将模板定义移动到一个单独的编译单元中时,我遇到了一些问题。我试图将模板实现移动到一个单独的文件中,以便为大多数依赖类启用前向声明。以下是我试图实现的一个示例:

// Impl.h
#pragma once

struct A {
    struct {
        int value;
    } valueA;
};

struct B {
    struct {
        int value;
    } valueB;
};

template<typename T>
int GetValue(T const &value);

// Impl.cpp
#include "Impl.h"
#include <type_traits>

using std::enable_if_t;
using std::remove_reference_t;

template<typename T, typename U, U(T::*Value)>
static inline int GetValueImpl(T const &value) {
    return (value.*Value).value;
}

template<typename T>
enable_if_t<T::valueA, int> GetValue(T const &value) {
    static constexpr auto T::*const Value = &T::valueA;
    typedef remove_reference_t<decltype(value.*Value)> ValueType;
    return GetValueImpl<T, ValueType, Value>(value);
}

template<typename T>
enable_if_t<T::valueB, int> GetValue(T const &value) {
    static constexpr auto T::*const Value = &T::valueB;
    typedef remove_reference_t<decltype(value.*Value)> ValueType;
    return GetValueImpl<T, ValueType, Value>(value);
}

template<> int GetValue(A const &); // C2912 here
template<> int GetValue(B const &); // C2912 here
//Impl.h
#布拉格语一次
结构A{
结构{
int值;
}瓦卢亚;
};
结构B{
结构{
int值;
}valueB;
};
模板
int GetValue(T常量和值);
//Impl.cpp
#包括“Impl.h”
#包括
使用std::enable_if_t;
使用std::删除\u引用\u t;
模板
静态内联int GetValueImpl(T常量和值){
返回值(value.*value).value;
}
模板
如果获取值(常量和值),则启用{
静态constexpr auto T::*const Value=&T::valueA;
类型定义删除参考值类型;
返回GetValueImpl(值);
}
模板
如果获取值(常量和值),则启用{
静态constexpr auto T::*const Value=&T::valueB;
类型定义删除参考值类型;
返回GetValueImpl(值);
}
模板int GetValue(常量&);//这里是C2912
模板int GetValue(B常量&);//这里是C2912

我使用的是VS2017u2,出现错误C2912:explicitt专门化“int GetValue(const A&)”不是函数模板的专门化。有人知道如何在单独的编译单元中使用这些定义吗?

当您编写
enable\u if\u t
时,它正在检查
t
的一个名为
valueA
的静态成员(这可能是一个
静态constexpr bool valueA=/*真或假*
,就像
T
使用T=std::is_same;时
T::value
的意思一样)

要实际检查它是否有名为
valueA
valueB
的成员,请将其置于一个上下文中,如果该成员不存在,则会出现替换错误,或者
true
。类似于:

// Pointers to member variables can never be null
// so these will always be enabled if `valueA` or
// `valueB` exist in the first place
enable_if_t<&T::valueA != nullptr, int>
enable_if_t<&T::valueB != nullptr, int>

// But that also allows pointers to static members
// so if you don't want that, you can do something else.
// Like checking if `&T::member` is a pointer to a member
// (But this is probably overkill as you have a specific set
// of types and none of those names are ever static members
// and if you didn't there is a small caveat with
// an overloaded `operator&` but that doesn't really matter)
enable_if_t<std::is_same_v<decltype(&T::valueA), decltype(T::valueA) T::*>, int>
enable_if_t<std::is_same_v<decltype(&T::valueB), decltype(T::valueB) T::*>, int>

我想您应该知道:,不是吗?getvalue模板impls的任何内容都不要求A或B不进行前向声明?
template int GetValue(A const &);  // No `<>`
template int GetValue(B const &);
#include <type_traits>
#include "Impl.h"

using std::enable_if_t;
using std::remove_reference_t;

template<typename T, typename U, U(T::*Value)>
static inline int GetValueImpl(T const &value) {
    return (value.*Value).value;
}

template<typename T>
enable_if_t<std::is_same_v<decltype(&T::valueA), decltype(T::valueA) T::*>, int> GetValueImpl2(T const &value) {
    static constexpr auto T::*const Value = &T::valueA;
    using ValueType = decltype(T::valueA);
    return GetValueImpl<T, ValueType, Value>(value);
}

template<typename T>
enable_if_t<std::is_same_v<decltype(&T::valueB), decltype(T::valueB) T::*>, int> GetValueImpl2(T const &value) {
    static constexpr auto T::*const Value = &T::valueB;
    using ValueType = decltype(T::valueB);
    return GetValueImpl<T, ValueType, Value>(value);
}

template<typename T>
int GetValue(T const&value) {
    return GetValueImpl2(value);
}


template int GetValue<A>(A const &);
template int GetValue<B>(B const &);