检查是否定义了类型

时间:2016-10-02 12:00:57

标签: c++ templates typetraits incomplete-type

考虑这个例子:

#include <iostream>
#include <type_traits>

template <class, class = void>
struct is_defined : std::false_type
{ };

template <class T>
struct is_defined<T,
    std::enable_if_t<std::is_object<T>::value &&
                    !std::is_pointer<T>::value
        >
    > : std::true_type
{
private:
    static const T test; //try to create incomplete type member
};

struct defined { };

struct forward_declared;

int main()
{
    std::cout << std::boolalpha
              << is_defined<defined>::value << std::endl
              << is_defined<forward_declared>::value << std::endl;
}

两者的输出均为true。我想如果我尝试使struct成员不完整,那么这个模板特化将从重载集中丢弃。但事实并非如此。删除static const会导致不完整类型的编译时错误。这种方法有什么问题,如果可能的话,怎么能实现呢?

3 个答案:

答案 0 :(得分:11)

试试这个:

SELECT * FROM
(
    select 
    n.ArticleID, n.Title, n.ArticleImage, cl.CategoryName
    from 
    News as n
    inner join 
    Categories as c on n.ArticleID = c.ArticleID
    inner join 
    CategoryList as cl on cl.CategoryID = c.CategoryID 
    where cl.CategoryName = 'Hot' 
    group by 
    n.ArticleID, n.Title, n.ArticleImage, cl.CategoryName
) AS A
INNER JOIN
(
    select 
    n.ArticleID, n.Title, n.ArticleImage, cl.CategoryName
    from 
    News as n
    inner join 
    Categories as c on n.ArticleID = c.ArticleID
    inner join 
    CategoryList as cl on cl.CategoryID = c.CategoryID 
    where cl.CategoryName = 'New'
    group by 
    n.ArticleID, n.Title, n.ArticleImage, cl.CategoryName
) AS B ON A.ArticleID = B.ArticleID

答案 1 :(得分:4)

一般情况下,在这种情况下,您可以使用一些不接受不完整类型的操作符来表示您的sfinae表达式。
例如,您可以使用typeid

#include <iostream>
#include <type_traits>
#include <utility>

template<typename T, typename = void>
constexpr bool is_defined = false;

template<typename T>
constexpr bool is_defined<T, decltype(typeid(T), void())> = true;

struct defined { };
struct forward_declared;

int main()
{
    std::cout << std::boolalpha
              << is_defined<defined> << std::endl
              << is_defined<forward_declared> << std::endl;
}

正如其他人所说,另一个有效运算符是sizeof

答案 2 :(得分:1)

关于问题“这种方法有什么问题......” 当我们进行静态const T检验时;它不是is_defined&lt; ...&gt;的一部分我们实际上必须在其他地方定义静态成员is_defined&lt; ...&gt; :: test,并且只在那个“else”的地方我们需要T来完成类型。 is_defined&LT; ...&GT; class编译只是因为静态成员大小对is_defined&lt; ...&gt;没有影响大小

去除静态const会导致T检验;成为is_defined&lt; ...&gt;的成员(并且要影响is_defined&lt; ...&gt;大小)因此T必须是完整类型才能具有已知大小。

更新注释:如果在模板专业化中声明类成员,SFINAE不会因为这也不是“参数替换”,也不是“SFINAE表达式”(也不是功能要超载!)。相反,它是某种“SFINAE字段声明” - 在替换失败的情况下,标准不是“非错误”。