English 中文(简体)
How to check at compile time that an expression is illegal?
原标题:

I have a problem in my application where I d like to assert that a function application would be rejected by the compiler. Is there a way to check this with SFINAE?

For example, assume that I d like to validate that std::transform to a const range is illegal. Here s what I have so far:

#include <algorithm>
#include <functional>
#include <iostream>

namespace ns
{

using std::transform;

template<typename Iterator1, typename Iterator2, typename UnaryFunction>
  struct valid_transform
{
  static Iterator1 first1, last1;
  static Iterator2 first2;
  static UnaryFunction f;

  typedef Iterator2                   yes_type;
  typedef struct {yes_type array[2];} no_type;

  static no_type transform(...);

  static bool const value = sizeof(transform(first1, last1, first2, f)) == sizeof(yes_type);
};

}

int main()
{
  typedef int *iter1;
  typedef const int *iter2;
  typedef std::negate<int> func;

  std::cout << "valid transform compiles: " << ns::valid_transform<iter1,iter1,func>::value << std::endl;

  std::cout << "invalid transform compiles: " << ns::valid_transform<iter1,iter2,func>::value << std::endl;

  return 0;
}

Unfortunately, my trait rejects both the legal and the illegal cases. The result:

$ g++ valid_transform.cpp 
$ ./a.out 
valid transform compiles: 0
invalid transform compiles: 0
最佳回答

Your question is similar to SFINAE + sizeof = detect if expression compiles.

Summary of that answer: sizeof evaluates the type of the expression passed to it, including instantiating a function template, but it does not generate a function call. This is the reason behind Lol4t0 s observations that sizeof(std::transform(iter1(), iter1(), iter2(), func())) compiles even if std::transform(iter1(), iter1(), iter2(), func()) does not.

Your concrete problem can be solved by evaluating the template from Lol4t0 s answer for any output range that is to be supplied to std::transform. However, the general problem of verifying in a template that a function call will compile appears to be impossible to be solved with the sizeof + SFINAE trick. (it would require a compile-time expression that is derivable from a run-time function call).

You might want to try ConceptGCC to see if this allows you to express the requisite compile-time checking in a more convenient way.

问题回答

In my answer, I dd like to focus on problem, how to determine, if given iterator constant: std::is_const was mentioned, but it does not work in this case for me (gcc 4.7).

I assume, it is implemeted like

template <typename T>
struct is_const
{
    enum {value = false };
};

template <typename T>
struct is_const<const T>
{
    enum {value = true };

};

Now, one cannot check reference types with this struct, they would not match specialization, because const T would match int& const, that is constant reference to int, not const int&, that is reference to constant int, and first have no any sense.

Ok, but we are able to determine, if iterator is constant with the follwing struct:

template <typename Iterator>
struct is_iterator_constant
{
    typedef char yes_type;
    typedef struct{ char _[2];}  no_type;
    template <typename T>
    static no_type test(T&);

    template <typename T>
    static yes_type test(...);

    enum {value = sizeof(test<typename std::iterator_traits<Iterator>::value_type>(*Iterator())) == sizeof(yes_type) };

};

C++20 concepts have made it much easier to check for expression validity. Your solution with the member detector idiom works, but is much more difficult and much less efficient than a concept with requires expression:

template <typename Iter1, typename Iter2, typename UnaryFunction>
concept valid_transform = requires (Iter1 first1, Iter1 last1, Iter2 first2, UnaryFunction f) {
    transform(first1, last1, first2, f);
};

If you were really serious about this constraint, you would probably build a concept which includes all the constraints of the std::ranges::transform function template.





相关问题
Undefined reference

I m getting this linker error. I know a way around it, but it s bugging me because another part of the project s linking fine and it s designed almost identically. First, I have namespace LCD. Then I ...

C++ Equivalent of Tidy

Is there an equivalent to tidy for HTML code for C++? I have searched on the internet, but I find nothing but C++ wrappers for tidy, etc... I think the keyword tidy is what has me hung up. I am ...

Template Classes in C++ ... a required skill set?

I m new to C++ and am wondering how much time I should invest in learning how to implement template classes. Are they widely used in industry, or is this something I should move through quickly?

Print possible strings created from a Number

Given a 10 digit Telephone Number, we have to print all possible strings created from that. The mapping of the numbers is the one as exactly on a phone s keypad. i.e. for 1,0-> No Letter for 2->...

typedef ing STL wstring

Why is it when i do the following i get errors when relating to with wchar_t? namespace Foo { typedef std::wstring String; } Now i declare all my strings as Foo::String through out the program, ...

C# Marshal / Pinvoke CBitmap?

I cannot figure out how to marshal a C++ CBitmap to a C# Bitmap or Image class. My import looks like this: [DllImport(@"test.dll", CharSet = CharSet.Unicode)] public static extern IntPtr ...

Window iconification status via Xlib

Is it possible to check with the means of pure X11/Xlib only whether the given window is iconified/minimized, and, if it is, how?

热门标签