C++ 我是否正确地排除了基数';s fn()函数?

C++ 我是否正确地排除了基数';s fn()函数?,c++,visual-c++,c++14,sfinae,crtp,C++,Visual C++,C++14,Sfinae,Crtp,我正试图做一些有趣的事情,结果突然发生了。我试过了,没有编译或运行时错误。(链接至rextester.com演示) #包括 #包括 int fn1(){return 1;} int fn2(int){return 2;} 模板 类测试库 { 模板 int fn() { 返回FN(); } 公众: int fn_间接法() { 返回static_cast(this)->fn(); } }; 模板 派生类测试:公共测试库 { 公众: 指定的静态constexpr bool fn_=false; };

我正试图做一些有趣的事情,结果突然发生了。我试过了,没有编译或运行时错误。(链接至rextester.com演示)

#包括
#包括
int fn1(){return 1;}
int fn2(int){return 2;}
模板
类测试库
{
模板
int fn()
{
返回FN();
}
公众:
int fn_间接法()
{
返回static_cast(this)->fn();
}
};
模板
派生类测试:公共测试库
{
公众:
指定的静态constexpr bool fn_=false;
};
模板
派生类测试
:公共测试基地
{
使用基础=测试基础;
朋友群;
公众:
指定的静态constexpr bool fn_=真;
int fn()
{
返回FN(1);
}
};
内部主(空)
{
测试_导出x1;
测试_导出的x2;

std::cout您正在使用的构造称为Expression SFINAE。Visual Studio在2017年之前不会向声明。Visual Studio 2015的更新启用了部分支持(请阅读更多信息,)。然而,要使其在所有版本的MSVC中都能正常工作,需要创建不涉及表达式的变通方法,例如在模板专用化参数内。要在您的情况下实现此目的,可以使用模式匹配和附加间接层(例如std::integral_常量):

#包括
#包括
int fn1(){return 1;}
int fn2(int){return 2;}
模板
类测试库
{
模板
int fn()
{
返回FN();
}
公众:
int fn_间接法()
{
返回static_cast(this)->fn();
}
};
模板
派生类测试:公共测试库
{
公众:
指定的静态constexpr bool fn_=false;
};
模板
派生类测试
:公共测试基地
{
使用基础=测试基础;
朋友群;
公众:
指定的静态constexpr bool fn_=真;
int fn()
{
返回fn2(1);
}
};
内部主(空)
{
测试_导出x1;
测试_导出的x2;

std::cout看起来MSVC没有使用
test_派生的
部分专门化,您可以通过打印
x2.fn_指定的
看到。我看到MSVC 2015“部分支持表达式SFINAE”-我不知道这是否是问题所在。@aschepler,你从哪里得到这句话的?好的,我已经提交了一个bug。如果其他人想提高它的优先级以使它得到修复,那就太好了。但是我在“支持”或“不支持”中都没有看到这种情况示例。我尝试使用VC++2017,至少编译器build 19.10.25019.0能够编译此代码。这意味着VC++2015不会看到此修复。因此,模式匹配在SFINAE失败的地方起作用?有趣的是。SFINAE表达式失败(
FN==&fn2
内部专用化)由于MSVC不隐藏他们不支持它。不知道他们没有隐藏事实。)表达式没有失败,我认为这是模板参数列表中的比较。不需要使用间接,只是不要比较指针,使用模式匹配直到C++ 2017。@阿德里安特别注意到[ 1 ]。:
我们计划在2015年RTM后立即在编译器中实现表达式SFINAE,并计划在2015年的更新中交付,支持生产使用。(但不一定是2015年的更新1。可能需要更长的时间。)
@Adrian PS comparison是一个表达式,在模板专门化的上下文中,参数是一个表达式sfinae。。。
#include <type_traits>
#include <iostream>

int fn1()    { return 1; }
int fn2(int) { return 2; }

template <typename FN_T, FN_T FN, typename DERIVED>
class test_base
{
    template <typename T = DERIVED, typename = std::enable_if_t<!T::fn_specified>>
    int fn()
    {
        return FN();
    }

public:
    int fn_indirect()
    {
        return static_cast<DERIVED*>(this)->fn();
    }
};

template <typename FN_T, FN_T FN, typename ENABLER = void>
class test_derived : public test_base<FN_T, FN, test_derived<FN_T, FN>>
{
public:
    static constexpr bool fn_specified = false;
};

template <typename FN_T, FN_T FN>
class test_derived<FN_T, FN, std::enable_if_t<FN == &fn2>>
    : public test_base<FN_T, FN, test_derived<FN_T, FN>>
{
    using base = test_base<FN_T, FN, test_derived<FN_T, FN>>;
    friend base;

public:
    static constexpr bool fn_specified = true;
    int fn()
    {
        return FN(1);
    }
};

int main(void)
{
    test_derived<decltype(&fn1), &fn1> x1;
    test_derived<decltype(&fn2), &fn2> x2;

    std::cout << x1.fn_indirect() << " ";

    // comment next line out and it'll work in VC++
    std::cout << x2.fn_indirect() << std::endl;
    return 0;
}
#include <type_traits>
#include <iostream>

int fn1()    { return 1; }
int fn2(int) { return 2; }

template <typename FN_T, FN_T FN, typename DERIVED>
class test_base
{
    template <typename T = DERIVED, typename = std::enable_if_t<!T::fn_specified>>
    int fn()
    {
        return FN();
    }

public:
    int fn_indirect()
    {
        return static_cast<DERIVED*>(this)->fn();
    }
};

template <class FN_T>
class test_derived : public test_base<typename FN_T::value_type, FN_T::value, test_derived<FN_T>>
{
public:
    static constexpr bool fn_specified = false;
};

template <typename FN_T>
class test_derived<std::integral_constant<FN_T, &fn2>>
    : public test_base<FN_T, &fn2, test_derived<std::integral_constant<FN_T, &fn2>>>
{
    using base = test_base<FN_T, &fn2, test_derived<std::integral_constant<FN_T, &fn2>>>;
    friend base;

public:
    static constexpr bool fn_specified = true;
    int fn()
    {
        return fn2(1);
    }
};

int main(void)
{
    test_derived<std::integral_constant<decltype(&fn1), &fn1>> x1;
    test_derived<std::integral_constant<decltype(&fn2), &fn2>> x2;

    std::cout << x1.fn_indirect() << " ";

    // comment next line out and it will work
    std::cout << x2.fn_indirect() << std::endl;
    return 0;
}