C++ Sfinae类型特征检测模板功能不';t与std::forward一起工作

C++ Sfinae类型特征检测模板功能不';t与std::forward一起工作,c++,c++11,templates,clang,sfinae,C++,C++11,Templates,Clang,Sfinae,我最近尝试创建一个sfinae类型trait来检测一个类是否包含一个名为construct的特定模板静态函数 我带来了这个实现: template<typename T, typename... Args> struct has_template_construct_helper { private: template<typename U, typename... As> static std::true_type test(decltype(&

我最近尝试创建一个sfinae类型trait来检测一个类是否包含一个名为
construct
的特定模板静态函数

我带来了这个实现:

template<typename T, typename... Args>
struct has_template_construct_helper {
private:
    template<typename U, typename... As>
    static std::true_type test(decltype(&U::template construct<As...>)*);

    template<typename...>
    static std::false_type test(...);

public:
    using type = decltype(test<T, Args...>(nullptr));
};

template<typename T, typename... Args>
using has_template_construct = typename has_template_construct_helper<T, Args...>::type;

我不太清楚为什么您的代码在clang++中失败(或在g++中传递)。但这里有一个更简单的选择

#include <type_traits>
#include <tuple>
#include <string>

template <typename... T>
using void_t = void;

class Stat {
public:
    template <typename... T>
    static auto construct(int a, double b, T&&... t) ->
      decltype(std::make_tuple(1, 2.3, t...))
    {
      return std::make_tuple(1, 2.3, std::forward<T>(t)...);
    }
};

template <typename Class, typename... Args>
constexpr auto does_have_construct(int)
    -> decltype(&Class::template construct<Args...>, true)
{
    return true;
}

template <typename Class, typename... Args>
constexpr bool does_have_construct(long) { return false; }

class Stat2 {};

int main() {
    static_assert(does_have_construct<Stat, std::string>(0), "Nope!");

    return 0;
}

正如您所看到的,在这种情况下,我们不必采取额外的步骤来愚弄编译器。

取消注释
test(…)
并查看替换过程中的实际错误。这会有帮助的。“不适用于std::forward”到底是什么意思?没有一种类型不能在编译时已知结果的情况下调用std::forward。我认为这是clang中的一个bug。添加转发引用使其认为构造方法存在过载,因此抛出错误。。。您确定在正文中使用forward而在返回类型中不使用forward应该有效吗?大多数情况下是的,但如果它解析为不同的函数,可能会导致隐藏的bug或编译错误吗?@GuillaumeRacicot:是的,我不是很确定,这就是为什么我写了“但是,我现在不确定代码的正确性!!”:)。但是,c++14方式应该不会给您带来任何问题。我真的希望有人能在这个问题上与克朗展开讨论。我在那上面找不到什么。
struct TestStruct {
    template<typename... Args>
    static auto construct(int a, double b, Args&&... args) -> decltype(std::make_tuple(a, b, std::forward<Args>(args)...))
    {
        return std::make_tuple(1, 2.3, std::forward<Args>(args)...);
    }
};

// fires on clang :(
static_assert(has_template_construct<TestStruct, std::string>::value, "Don't pass the test");
struct TestStruct {
    template<typename... Args>
    static auto construct(int a, double b, Args&&... args) -> decltype(std::make_tuple(a, b, std::declval<Args>()...))
    {
        return std::make_tuple(1, 2.3, std::forward<Args>(args)...);
    }
};

// uh?? Works in clang?
static_assert(has_template_construct<TestStruct, std::string>::value, "Don't pass the test");
#include <type_traits>
#include <tuple>
#include <string>

template <typename... T>
using void_t = void;

class Stat {
public:
    template <typename... T>
    static auto construct(int a, double b, T&&... t) ->
      decltype(std::make_tuple(1, 2.3, t...))
    {
      return std::make_tuple(1, 2.3, std::forward<T>(t)...);
    }
};

template <typename Class, typename... Args>
constexpr auto does_have_construct(int)
    -> decltype(&Class::template construct<Args...>, true)
{
    return true;
}

template <typename Class, typename... Args>
constexpr bool does_have_construct(long) { return false; }

class Stat2 {};

int main() {
    static_assert(does_have_construct<Stat, std::string>(0), "Nope!");

    return 0;
}
class Stat {
public:
    template <typename... T>
    static auto construct(int a, double b, T&&... t)
    {
      return std::make_tuple(1, 2.3, std::forward<T>(t)...);
    }
};