C++11 静态断言类继承以终止编译(通过SFINAE?) 目标

C++11 静态断言类继承以终止编译(通过SFINAE?) 目标,c++11,sfinae,static-assert,C++11,Sfinae,Static Assert,假设模板类神话有大量使用语句,例如使用T::my_def或使用T::my_other_def。由于明显的原因,如果T没有定义my_def和my_other_def,编译将失败然而,实际用例中的编译失败会导致数百个错误,使用户难以理解实际问题。虽然编译失败是“足够好”,但我真的很想通过某种聪明的代理类找到一种提前终止编译的方法。首先,为了完整性,包括SFINAE设置。第二个是如何使用函数实现这一点的推论示例。然后是我的尝试,以及怀疑为什么这实际上不可能的原因(但我希望是错误的) 注意:这是一个“严

假设
模板类神话
有大量
使用
语句,例如
使用T::my_def
使用T::my_other_def
。由于明显的原因,如果
T
没有定义
my_def
my_other_def
,编译将失败然而,实际用例中的编译失败会导致数百个错误,使用户难以理解实际问题。虽然编译失败是“足够好”,但我真的很想通过某种聪明的代理类找到一种提前终止编译的方法。首先,为了完整性,包括SFINAE设置。第二个是如何使用函数实现这一点的推论示例。然后是我的尝试,以及怀疑为什么这实际上不可能的原因(但我希望是错误的)

注意:这是一个“严格”的C++11项目(但我不反对导入类型,例如,
std::void\t
已经成功了,尽管我在
std::conditional
失败)。如果您知道这些内容,请跳到第2节,并注意:

  • is_valid()
    是一个
    静态constexpr bool
    函数,其行为类似于
    std::conditional
    ,检查
    my_def
    my_other_def
    是否为
    T
    中的有效类型名
1:SFINAE设置(C++17个后端端口和组件) 4.一些简单的测试
///////////////////////////////////////////////////////
//测试
结构良好{
使用my_def=float;
使用my_other_def=int;
};
使用my_def=double;}构造几乎_1{;
结构几乎2{使用my_other_def=bool;};
结构错误{};
int main(int argc,常量字符**argv){
//健康检查

std::cout希望有另一种方法,但似乎最简单的解决方案是另一种方法:用户应该实例化的类没有实际的实现,而
内部
类就完成了这一切

namespace internal {
    template <class T, bool valid>
    struct TheClass {
        static_assert(valid, "Template 'class T' must have static types `my_def` and `my_other_def`.");
    };

    template <class T>
    struct TheClass<T, true> {
        // compiler warning 2
        using my_def = typename T::my_def;
        // compiler warning 3
        using my_other_def = typename T::my_other_def;

        std::string message() {
            return "work gets done";
        }
    };
}

template <class T>
struct TheClass : internal::TheClass<T, is_valid<T>()> { };

struct Good {
    using my_def = float;
    using my_other_def = int;
};
struct Almost_1 { using my_def = double; };

int main(int argc, const char **argv) {
    TheClass<Good> g;
    std::cout << "Good message: " << g.message() << std::endl;

    // only one static assert
    TheClass<Almost_1> a1;
    return 0;
}
名称空间内部{
模板
结构类{
static_assert(有效,“模板'class T'必须具有静态类型'my_def'和'my_other_def');
};
模板
结构类{
//编译器警告2
使用my_def=typename T::my_def;
//编译器警告3
使用my_other_def=typename T::my_other_def;
std::string消息(){
返回“完成工作”;
}
};
}
模板
结构类:内部::类{};
结构良好{
使用my_def=float;
使用my_other_def=int;
};
使用my_def=double;}构造几乎_1{;
int main(int argc,常量字符**argv){
g类;

std::cout希望有另一种方法,但似乎最简单的解决方案是另一种方法:用户应该实例化的类没有实际的实现,而
内部
类就完成了这一切

namespace internal {
    template <class T, bool valid>
    struct TheClass {
        static_assert(valid, "Template 'class T' must have static types `my_def` and `my_other_def`.");
    };

    template <class T>
    struct TheClass<T, true> {
        // compiler warning 2
        using my_def = typename T::my_def;
        // compiler warning 3
        using my_other_def = typename T::my_other_def;

        std::string message() {
            return "work gets done";
        }
    };
}

template <class T>
struct TheClass : internal::TheClass<T, is_valid<T>()> { };

struct Good {
    using my_def = float;
    using my_other_def = int;
};
struct Almost_1 { using my_def = double; };

int main(int argc, const char **argv) {
    TheClass<Good> g;
    std::cout << "Good message: " << g.message() << std::endl;

    // only one static assert
    TheClass<Almost_1> a1;
    return 0;
}
名称空间内部{
模板
结构类{
static_assert(有效,“模板'class T'必须具有静态类型'my_def'和'my_other_def');
};
模板
结构类{
//编译器警告2
使用my_def=typename T::my_def;
//编译器警告3
使用my_other_def=typename T::my_other_def;
std::string消息(){
返回“完成工作”;
}
};
}
模板
结构类:内部::类{};
结构良好{
使用my_def=float;
使用my_other_def=int;
};
使用my_def=double;}构造几乎_1{;
int main(int argc,常量字符**argv){
g类;

std::我可能处于愚蠢的模式,但我找不到你在哪里陈述了你真正想要做的事情…不,是我!我像赫克一样试图使问题尽可能简短,这样做有效地消除了实际问题。通过与函数版本n起作用。我可能处于愚蠢的模式,但我找不到你在哪里陈述了你真正想要做的事情…不,是我!我像赫克一样试图使问题尽可能简短,这样做有效地消除了实际问题。通过与函数版本进行比较,最后的问题引导和概要现在应该让事情更清楚了作品
///////////////////////////////////////////////////////
// Need some more proxying?
namespace internal {
    template <class T, bool valid>
    struct TheClass {
        // compiler warning 1 (seek termination here)
        static_assert(valid, "You have been asserted.");
    };

    template <class T>
    struct TheClass<T, true> {
        std::string message() { return "You are valid."; }
    };
}

template <class T>
struct TheClass : public internal::TheClass<T, is_valid<T>()> {
    // compiler warning 2
    using my_def = typename T::my_def;
    // compiler warning 3
    using my_other_def = typename T::my_other_def;

    std::string message() {
        return internal::TheClass<T, is_valid<T>()>::message();
    }
};
///////////////////////////////////////////////////////
// The tests
struct Good {
    using my_def = float;
    using my_other_def = int;
};
struct Almost_1 { using my_def = double; };
struct Almost_2 { using my_other_def = bool; };
struct Bad {};

int main(int argc, const char **argv) {
    // sanity checks
    std::cout << std::boolalpha
              << "Good:     " << is_valid<Good>()     << std::endl
              << "Almost_1: " << is_valid<Almost_1>() << std::endl
              << "Almost_2: " << is_valid<Almost_2>() << std::endl
              << "Bad:      " << is_valid<Bad>()      << std::endl;

    // in function land, uncomment these and it will
    // only produce the single static_assert for valid<T>
    // rather than continuing on for breaking T
    // validate_wrapper<Good>();
    // validate_wrapper<Almost_1>();

    // At least this works.
    TheClass<Good> g;
    std::cout << "Good message: " << g.message() << std::endl;

    // I would like to achieve just one error from static_assert
    // comment out to see that `validate_wrapper<Almost_1>` will
    // terminate early (as desired)
    TheClass<Almost_1> a1;
    return 0;
}
namespace internal {
    template <class T, bool valid>
    struct TheClass {
        static_assert(valid, "Template 'class T' must have static types `my_def` and `my_other_def`.");
    };

    template <class T>
    struct TheClass<T, true> {
        // compiler warning 2
        using my_def = typename T::my_def;
        // compiler warning 3
        using my_other_def = typename T::my_other_def;

        std::string message() {
            return "work gets done";
        }
    };
}

template <class T>
struct TheClass : internal::TheClass<T, is_valid<T>()> { };

struct Good {
    using my_def = float;
    using my_other_def = int;
};
struct Almost_1 { using my_def = double; };

int main(int argc, const char **argv) {
    TheClass<Good> g;
    std::cout << "Good message: " << g.message() << std::endl;

    // only one static assert
    TheClass<Almost_1> a1;
    return 0;
}